1
#include <functional>
#include <memory>
#include <iostream>

using namespace std;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    return 0;
}

GCC objects to the second bind statement being assigned to the function object with the shared_ptr signature. Here is the error output.

/usr/include/c++/4.5/functional:2103|6|instantiated from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = std::_Bind(std::_Placeholder<1>)>, _Res = void, _ArgTypes = {std::shared_ptr}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function)>::_Useless]’| /home/craig/work/litd/test/main.cpp:29|97|instantiated from here| /usr/include/c++/4.5/functional|1713|error: no match for call to ‘(std::_Bind(std::_Placeholder<1>)>) (std::shared_ptr)’| ||=== Build finished: 1 errors, 0 warnings ===|

Edit: More mystery, when I change the include headers to their tr1 equivalents, it does compile.

#include <tr1/functional>
#include <tr1/memory>
#include <iostream>

using namespace std::tr1;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    return 0;
}
3
  • It might help to post the actual error message, too. Commented Sep 13, 2011 at 20:56
  • It might need help with the template std::function<void(typename std::shared_ptr<Foo>)> f2(bind(&Foo::Bar, std::placeholders::_1)); perhaps? Commented Sep 13, 2011 at 21:22
  • Still not happy. /home/craig/work/litd/test/main.cpp||In function ‘int main()’:| /home/craig/work/litd/test/main.cpp|29|error: typedef declaration invalid in parameter declaration| /home/craig/work/litd/test/main.cpp|29|error: expected ‘::’ before ‘f2’| /home/craig/work/litd/test/main.cpp|29|error: ‘std::function<void()>::f2’ has not been declared| /home/craig/work/litd/test/main.cpp|29|error: expected ‘)’ before ‘(’ token| ||=== Build finished: 4 errors, 0 warnings ===| Commented Sep 13, 2011 at 21:45

2 Answers 2

1

It looks like a bug in g++'s implementation of std::function or maybe std::bind, depending on whether you can invoke the object returned by bind(&Foo::Bar, placeholders::_1) with foo; if this works:

auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(foo);

then it would seem that g++'s std::function implementation is incomplete. Otherwise, it would seem that the implementation of std::bind is incomplete.

[20.8.9.1.2] Function template bind states:

template<class F, class... BoundArgs>
  unspecified bind(F&& f, BoundArgs&&... bound_args);

...

Returns: A forwarding call wrapper g with a weak result type (20.8.2). The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of::type)

[20.8.2] Requirements states:

Define INVOKE(f, t1, t2, ..., tN) as follows:

(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

...

When binding &Foo::Bar, the returned "forwarding call wrapper" takes one argument, u1. Call its type U1. Further on in [20.8.9.1.2] it states that because the 1st template argument type in BoundArgs was the _1 placeholder type, the type V1 is U1&&.

Passing a std::shared_ptr<Foo> to the forwarding call wrapper returned by bind(&Foo::Bar, placeholders::_1) should be allowed because case 2 of [20.8.2] applies.

EDIT: I am using the same version of g++ as you, 4.5.2, on Windows (MinGW). For me, the following compiles just fine:

#include <functional>
#include <memory>
#include <iostream>

using namespace std;

class Foo
{
public:
    void Bar() { std::cout << "Foo::Bar" << std::endl; }
};

int main()
{
    shared_ptr<Foo> foo(new Foo);
    function<void(Foo*)> f1(bind(&Foo::Bar, placeholders::_1));
    //function<void(shared_ptr<Foo>)> f2(bind(&Foo::Bar, placeholders::_1));
    auto fn2 = bind(&Foo::Bar, placeholders::_1);
    fn2(foo);
    return 0;
}

It thus appears to be g++'s implementation of std::function that is to blame.

EDIT2: The following fails:

auto fn2 = bind(&Foo::Bar, placeholders::_1);
fn2(std::shared_ptr<Foo>(foo));

SO7408263.cpp:19:31: error: no match for call to '(std::_Bind(std::_Placeholder<1>)>) (std::shared_ptr)'

Perhaps it's std::bind after all.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer. Strange, it does not compile on my Ubuntu setup. Could different bits be broken on each platform?
@Craig: fn2(foo); does not compile on your Ubuntu setup? Strange. I thought that MinGW's version of libstdc++ is unmodified.
0

The function will expect ->* to be overloaded to use a pointer-to-member. I believe that shared_ptr does not provide this functionality. The TR1 specification might have mandated a specialization but the C++11 might not. In Visual Studio then the C++11 shared_ptr is defined to be their TR1 versions, which would explain the difference.

2 Comments

I have looked at both the g++ & vs2010 implementations of shared_ptr and neither seem to implement operator ->*.
@Craig: I also mentioned the possibility of a specialization.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.