If you know you aren't actually going to copy your function object then you can just wrap it in a type that makes the compiler think it's copyable:
struct ThrowOnCopy {
ThrowOnCopy() = default;
ThrowOnCopy(const ThrowOnCopy&) { throw std::logic_error("Oops!"); }
ThrowOnCopy(ThrowOnCopy&&) = default;
ThrowOnCopy& operator=(ThrowOnCopy&&) = default;
};
template
struct FakeCopyable : ThrowOnCopy
{
FakeCopyable(T&& t) : target(std::forward(t)) { }
FakeCopyable(FakeCopyable&&) = default;
FakeCopyable(const FakeCopyable& other)
: ThrowOnCopy(other), // this will throw
target(std::move(const_cast(other.target))) // never reached
{ }
template
auto operator()(Args&&... a)
{ return target(std::forward(a)...); }
T target;
};
template
FakeCopyable
fake_copyable(T&& t)
{ return { std::forward(t) }; }
// ...
doit( fake_copyable([p = std::move(p)] () { std::cout << *p << std::endl; }) );
The function template fake_copyable
creates a wrapper which is CopyConstructible
according to the compiler (and
) but cannot be copied at run-time.
If you store a FakeCopyable
in a std::function
and then end up copying the std::function
you will get a std::logic_error
thrown, but if you only move the std::function
everything will work OK.
The target(std::move(const_cast(other.target)))
looks worrying, but that initializer will never run, because the base class initializer will throw first. So the worrying const_cast
never really happens, it just keeps the compiler happy.