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
gwith a weak result type (20.8.2). The effect ofg(u1, u2, ..., uM)shall beINVOKE(fd, v1, v2, ..., vN, result_of::type)
[20.8.2] Requirements states:
Define
INVOKE(f, t1, t2, ..., tN)as follows:—
(t1.*f)(t2, ..., tN)whenfis a pointer to a member function of a classTandt1is an object of typeTor a reference to an object of typeTor a reference to an object of a type derived fromT;—
((*t1).*f)(t2, ..., tN)whenfis a pointer to a member function of a classTandt1is 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.
加载中,请稍侯......
精彩评论