开发者

Why does this code fragment compile with VS2010 but not GCC 4.5.2?

#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.

开发者_JAVA百科

/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;
}


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜