7

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 it finished with errors. I'm not sure if it is reasonable to paste the whole compilers output but generally

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 finished with errors:
source.cpp: In instantiation of 'X::X(T) [with T = std::_Bind(Y*)>]':
source.cpp:28:33: required from here
source.cpp:8:9: error: no match for call to '(std::_Bind_helper(Y*)>), X* const, std::_Bind(Y*)>&>::type {aka std::_Bind(Y*)>)>(X*, std::_Bind(Y*)>)>}) ()'

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

I would be grateful if someone help.

P.S. It compiles if I create an instance of X, passing function object or function pointer.

Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
orlin
  • 73
  • 1
  • 5

2 Answers2

4

I think they omitted an important bit of boost::bind when adopting it into std::bind, namely boost::protect(). Your code can be fixed like the following:

#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, by default, not evaluated, all other arguments are. Sometimes it is necessary not to evaluate arguments subsequent to the first, even when they are nested bind subexpressions. This can be achieved with the help of another function object, protect, that masks the type so that bind does not recognize and evaluate it. When called, protect simply forwards the argument list to the other function object unmodified.

The header boost/bind/protect.hpp contains an implementation of protect. To protect a bind function object from evaluation, use protect(bind(f, ...)).


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

template <typename T>
explicit X(T t)
{
    auto f = [t, this]() { this->invoke(t); };
    f();
}
// ...

X x([&y](){ y.foo(); });
Community
  • 1
  • 1
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • The upcoming Effective C++11: Content and Status is available as "Effective Modern C++". Items 34 is "prefer lambdas to std::bind", and concludes "Lamda are more readable, more expressive ...". – Jean Davy Feb 21 '15 at 16:08
  • @JeanDavy Was it not released a few months ago? – Maxim Egorushkin Feb 22 '15 at 01:54
  • Oup's, yes it is. I worked with Java and Python these last months and so I neglected C++, now that I'm back to my first true love ;-), I just bought it. – Jean Davy Feb 23 '15 at 08:25
2

The root cause of the problem seems to be the internal copying of its arguments performed by std::bind, with particular reference to t.

You may want to workaround it this way:

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

This will also work, but you won't be allowed to make the result of bind outlive the argument t (otherwise, you would be passing a dangling reference 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 for achieving what you are showing in your example. However, it emerged from the comments that your use case may be quite different (e.g. passing around the result of bind for later evaluation).

As correctly pointed out by Maxim Yegorushkin in his answer, the conceptually correct solution consists in using a construct such as Boost's protect.

In case you do not want to use Boost, it is quite easy to define your own protect() function using C++11's 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));
}

Eventually, this is how you could 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();
    }
};
Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • It solves a somewhat different problem, in my opinion. The original bind expression is self-contained in a sense that it stores copies of all arguments, so that the arguments can be destroyed. Your solutions omit copying the functor and relies that it is still in scope and alive at the time of the call. Realistically, there is no point in creating a bind expression and then immediately calling it. Rather you want to pass the functor created by bind somewhere else and often delay calling till later. – Maxim Egorushkin Feb 27 '13 at 15:41
  • @MaximYegorushkin: Indeed. Still, this is an effective workaround for the OP's use case. – Andy Prowl Feb 27 '13 at 15:43
  • Not sure if that is his real use case. See my updated previous comment. – Maxim Egorushkin Feb 27 '13 at 15:46
  • @MaximYegorushkin: I understood your comment. Based on the example the OP supplied, this provides a *workaround* (that's the word I used). I am not claiming it is a conceptually perfect solution. Especially with the first workaround I suggested, the OP is not forced to invoke the result of bind immediately; it can just copy the argument around separately. Again, I'm not claiming this solution is perfect, let alone better than yours, I'm just saying it provides a *workaround*. For instance, the OP might not want to use boost. – Andy Prowl Feb 27 '13 at 15:49
  • Thanks Andy, std::bind(&X::invoke, this, cref(t))() solves my problem. It is also will be useful if I intend to start a thread in the ctor, binding invoke() method as threads entry point. – orlin Feb 27 '13 at 21:17
  • @user2102602: No, you shouldn't do that. As mentioned in the answer, you would create a dangling reference. Let me edit. – Andy Prowl Feb 27 '13 at 21:19
  • Oh, yes in my case if I bind it to a thread, then invoke() will get a reference_wrapper, containing dangling argument. – orlin Feb 27 '13 at 21:54