How to bind a member function template passing an undefined call wrapper

I tried to compile the following example using VC11 and g ++ 4.7.2:

#include <functional> class X { public: template <typename T> explicit X(T t) { std::bind(&X::invoke<T>, this, t)(); } private: template <typename T> void invoke(T t) { t(); } }; class Y { public: void foo() { //... } }; int main() { Y y; X x(std::bind(&Y::foo, &y)); return 0; } 

but he ended up with errors. I'm not sure it is wise to embed all the output of the compilers, but usually

vc11 says:

error C2664: 'void std :: _ Pmf_wrap :: operator () (_ Farg0 &, _ V0_t) const': cannot convert parameter 3 from 'void' to 'std :: _ Bind, Y *, std :: _ Nil, std :: _ Nil, std :: _ Nil, std :: _ Nil, std :: _ Nil, std :: _ Nil> 'c: \ program files (x86) \ microsoft visual studio 11.0 \ vc \ include \ functional 1152 1 ConsoleApplication1 (Microsoft Visual C ++ Compiler Nov 2012 CTP)

and g ++:

Compilation completed with errors:
source.cpp: When creating 'X :: X (T) [with T = std :: _ Bind (Y *)>]':
source.cpp: 28: 33: required from here
source.cpp: 8: 9: error: no match for calling on '(std :: _ Bind_helper (Y *)>), X * const, std :: _ Bind (Y *)> &> :: type {aka std :: _ Bind (Y *)>)> (X *, std :: _ Bind (Y *)>)>}) () '

Is there any way to solve this problem. It is very important for me to save the main idea - a class that can be created with any called object (function object, function pointer or call wrapper returned by std::bind() ).

I would be grateful if someone would help.

PS It compiles if I create an instance of X by passing an object to a function or a function pointer.

+7
source share
2 answers

The root cause of the problem is the internal copying of its arguments by std::bind , with a special reference to t .

You might want a workaround:

  template <typename T> explicit X(T t) { std::bind(&X::invoke<T>, this, std::placeholders::_1)(t); // ^^^^^^^^^^^^^^^^^^^^^ ^ } 

This will also work, but you will not be able to make the bind result survive the t argument (otherwise you will pass a dangling link to invoke<T>() ):

  template <typename T> explicit X(T t) { std::bind(&X::invoke<T>, this, cref(t))(); // ^^^^^^^ } 

UPDATE:

The above solutions are workarounds that help achieve what you show in your example. However, it follows from the comments that your use case may be completely different (for example, passing a bind result for further evaluation).

As Maxim Egorushkin correctly pointed out in his answer, the conceptually correct solution is to use a design such as Boost protect .

If you don't want to use Boost, it's pretty simple to define your own protect() function using C ++ 11 variadic templates:

 // Imitates boost::protect, but with variadic templates and perfect forwarding namespace detail { template<typename F> struct protect { private: F _f; public: explicit protect(F f): _f(f) { } template<typename... Ts> auto operator () (Ts&&... args) -> decltype(_f(std::forward<Ts>(args)...)) { return _f(std::forward<Ts>(args)...); } }; } template<typename F> detail::protect<F> protect(F&& f) { return detail::protect<F>(std::forward<F>(f)); } 

In the end, so you can use it in your class, as Maxim suggested:

 class X { public: template <typename T> explicit X(T t) { auto pt = protect(t); std::bind(&X::invoke<decltype(pt)>, this, pt)(); } private: template <typename T> void invoke(T t) { t(); } }; 
+2
source

I think they missed the important boost::bind bit by accepting it in std::bind , namely boost::protect() . Your code can be fixed as follows:

 #include <boost/bind/protect.hpp> // ... X x(boost::protect(std::bind(&Y::foo, &y))); 

Or alternatively:

 template <typename T> explicit X(T t) { auto tt = boost::protect(t); auto f = std::bind(&X::invoke<decltype(tt)>, this, tt); f(); } 

See http://www.boost.org/doc/libs/1_53_0/libs/bind/bind.html

Although the first argument is not evaluated by default, all other arguments. Sometimes it is necessary not to evaluate arguments after the first, even if they are nested in sub-expressions of the binding. This can be achieved by using another function protector object that masks the type so that the binding does not recognize or evaluate it. When called, it protects simply forwarding the argument list to another function object without changes.

The boost / bind / protect.hpp header contains a security implementation. To protect the binding function object from evaluation, use protection (bind (f, ...)).


The upcoming Effective C ++ 11: Content and Status by Scott Meyers is going to recommend lambdas for std :: bind. In C ++ 11, you can simply:

 template <typename T> explicit X(T t) { auto f = [t, this]() { this->invoke(t); }; f(); } // ... X x([&y](){ y.foo(); }); 
+4
source

All Articles