Created
June 19, 2013 16:38
-
-
Save vmilea/5815777 to your computer and use it in GitHub Desktop.
how to wrap noncopyable functors as std::function
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "meta/FunctionTraits.h" | |
#include <utility> | |
#include <stdexcept> | |
#include <functional> | |
#include <string> | |
#include <cassert> | |
template <typename F> | |
class MoveOnCopyAdapter | |
{ | |
public: | |
MoveOnCopyAdapter(F&& f) | |
: mF(std::move(f)) { } | |
MoveOnCopyAdapter(MoveOnCopyAdapter&& other) | |
: mF(std::move(other.mF)) { } | |
MoveOnCopyAdapter& operator=(MoveOnCopyAdapter&& other) | |
{ | |
mF = std::move(other.mF); | |
return *this; | |
} | |
MoveOnCopyAdapter(const MoveOnCopyAdapter& other) | |
: mF(static_cast<F&&>(const_cast<F&>(other.mF))) | |
{ | |
throw std::logic_error("not copyable"); | |
} | |
MoveOnCopyAdapter& operator=(const MoveOnCopyAdapter& other) | |
{ | |
throw std::logic_error("not copyable"); | |
} | |
template <typename... Args> | |
auto operator()(Args&&... args) | |
-> typename std::result_of<F (Args...)>::type | |
{ | |
using namespace std; | |
return mF(std::forward<Args>(args)...); | |
} | |
private: | |
F mF; | |
}; | |
template <typename F> | |
auto asFunction(F&& f) | |
-> std::function<typename ut::FunctionTraits<F>::signature_type> | |
{ | |
static_assert (std::is_rvalue_reference<F&&>::value, "needs rvalue"); | |
return MoveOnCopyAdapter<F>(std::move(f)); | |
} | |
struct Appender | |
{ | |
std::string value; | |
Appender() { } | |
Appender(Appender&& other) | |
: value(std::move(other.value)) { } | |
const std::string& operator()(std::string s) | |
{ | |
return value += s; | |
} | |
private: | |
Appender(const Appender& ); | |
Appender& operator=(const Appender& ); | |
}; | |
int main() | |
{ | |
Appender a; | |
std::function<const std::string& (std::string)> f; | |
f = asFunction(std::move(a)); | |
f("123"); | |
// auto g = f; // throws | |
auto g = std::move(f); // ok | |
assert (g("456") == "123456"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The copy constructor has a problem. It will move other.mF before throwing the exception, and thus the original will be destroyed (i.e. in your example, if you catch the exception of
auto g = f;
and then callf
, it will result in undefined behavior), not only the "failed copy". My solution will not move the original, and I think also looks cleaner:As the function does not return, it does not have to hack some value having the correct type, but it still can have that return type.