1

The following code fails to compile using GCC with libstdc++ and using Clang with libc++:

#include <functional>

template<class F> class X {
public:
    static void foo(F f, int)
    {
        f();
    }
};

template<class F> void bar(F f)
{
    std::bind(&X<F>::foo, f, 2)();
}

void baz(int) {}

int main()
{
   bar(std::bind(&baz, 1));
}

As far as I understand std::bind(), this is supposed to be valid. Any ideas why it fails?

Here is the output from GCC 4.9:

t.cpp: In instantiation of ‘void bar(F) [with F = std::_Bind]’:
t.cpp:20:26:   required from here
t.cpp:13:31: error: no match for call to ‘(std::_Bind_helper, int), std::_Bind&, int>::type {aka std::_Bind, int))(std::_Bind, int)>}) ()’
     std::bind(&X::foo, f, 2)();
                               ^
In file included from t.cpp:1:0:
/usr/include/c++/4.9/functional:1248:11: note: candidates are:
     class _Bind
           ^
/usr/include/c++/4.9/functional:1319:2: note: template _Result std::_Bind::operator()(_Args&& ...) [with _Args = {_Args ...}; _Result = _Result; _Functor = void (*)(std::_Bind, int); _Bound_args = {std::_Bind, int}]
  operator()(_Args&&... __args)
  ^
/usr/include/c++/4.9/functional:1319:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.9/functional:1317:40: error: could not convert ‘std::_Mu, true, false>().std::_Mu::operator(), {}>((* & std::declval&>()), (* & std::declval&>()))’ from ‘void’ to ‘std::_Bind’
       std::declval&>() )... ) )>
                                        ^
/usr/include/c++/4.9/functional:1333:2: note: template _Result std::_Bind::operator()(_Args&& ...) const [with _Args = {_Args ...}; _Result = _Result; _Functor = void (*)(std::_Bind, int); _Bound_args = {std::_Bind, int}]
  operator()(_Args&&... __args) const
  ^
/usr/include/c++/4.9/functional:1333:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.9/functional:1331:40: error: could not convert ‘std::_Mu, true, false>().std::_Mu::operator(), {}>((* & std::declval&>()), (* & std::declval&>()))’ from ‘void’ to ‘std::_Bind’
       std::declval&>() )... ) )>
                                        ^
/usr/include/c++/4.9/functional:1347:2: note: template _Result std::_Bind::operator()(_Args&& ...) volatile [with _Args = {_Args ...}; _Result = _Result; _Functor = void (*)(std::_Bind, int); _Bound_args = {std::_Bind, int}]
  operator()(_Args&&... __args) volatile
  ^
/usr/include/c++/4.9/functional:1347:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.9/functional:1345:40: error: could not convert ‘std::_Mu, true, false>().std::_Mu::operator(), {}>((* & std::declval&>()), (* & std::declval&>()))’ from ‘void’ to ‘std::_Bind’
       std::declval&>() )... ) )>
                                        ^
/usr/include/c++/4.9/functional:1361:2: note: template _Result std::_Bind::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}; _Result = _Result; _Functor = void (*)(std::_Bind, int); _Bound_args = {std::_Bind, int}]
  operator()(_Args&&... __args) const volatile
  ^
/usr/include/c++/4.9/functional:1361:2: note:   template argument deduction/substitution failed:
/usr/include/c++/4.9/functional:1359:40: error: could not convert ‘std::_Mu, true, false>().std::_Mu::operator(), {}>((* & std::declval&>()), (* & std::declval&>()))’ from ‘void’ to ‘std::_Bind’
       std::declval&>() )... ) )>
Kristian Spangsege
  • 2,903
  • 1
  • 20
  • 43
  • 1
    Please don't expect us to *guess* the compiler errors. In other words, you should post them as well. – Nawaz May 04 '15 at 15:09
  • 1
    C++11? Stop using bind. It does magic. Instead use lambdas, which are now (or should soon be) familiar to C++ developers: `bind` is now an obscure function with lots of quirks. If you really, really need perfect forwarding type parameters, you do have to wait for C++14 or roll your own object, but that is a rare requirement. – Yakk - Adam Nevraumont May 04 '15 at 15:21
  • @Yakk, I agree that lambdas make `std::bind` mostly obsolete, however, as long as `std::bind` is part of the standard, it has to be implemented correctly by vendors, right? As far as I can see, there is a bug in both libstdc++ and in libc++, and I am not yet convinced that the other question is a true duplicate. – Kristian Spangsege May 04 '15 at 15:29
  • @KristianSpangsege It's not a bug, that's how `bind` is specified. – Barry May 04 '15 at 15:33
  • @Yakk, alright, would be awesome if you can you point me to the relevant part of the standard? – Kristian Spangsege May 04 '15 at 15:34
  • How not? You passed a bind expression to a bind. This does strange things. Particularly, the result of the sub-bind is used, instead of the sub-bind itself, as the input to the next bind. This is covered on [cppreference](http://en.cppreference.com/w/cpp/utility/functional/bind). No I don't feel like looking up the quote in the standard. It will be about `is_bind_expression` if you feel like doing it yourself. Again, the short version is, stop using `std::bind` unless you want to learn all of its really quirky features. – Yakk - Adam Nevraumont May 04 '15 at 15:39
  • @KristianSpangsege The key example from the [reference](http://en.cppreference.com/w/cpp/utility/functional/bind) is `auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);`. Note how the nested `std::bind(g, _3)` gets evaluated as a value - **NOT** a function. – Barry May 04 '15 at 15:47
  • Ok, I got it now :-) I.e., when a bind expression is bound as a an argument, the meaning is to evaluate the subsexpression in a delayed fashion, rather than passing the callable bind expression itself. Thanks @Barry. – Kristian Spangsege May 04 '15 at 16:02

0 Answers0