为什么这个代码片段用VS2010而不是GCC 4.5.2编译?

时间:2011-09-13 20:47:13

标签: c++ visual-studio-2010 function gcc bind

#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对象使用shared_ptr签名分配给函数对象的第二个绑定语句。这是错误输出。

  

/ usr / include / c ++ / 4.5 / functional:2103 | 6 |实例化   'std :: function&lt; _Res(_ArgTypes ...)&gt; :: function(_Functor,typename   std :: enable_if&lt;(!std :: is_integral&lt; _Functor&gt; :: value),   std :: function&lt; _Res(_ArgTypes ...)&gt; :: _ Useless&gt; :: type)[with _Functor =   std :: _ Bind(std :: _ Placeholder&lt; 1&gt;)&gt;,_Res   = void,_ArgTypes = {std :: shared_ptr},typename std :: enable_if&lt;(!   std :: is_integral&lt; _Functor&gt; :: value),std :: function&lt; _Res(_ArgTypes   ...)&gt; :: _ Useless&gt; :: type =   的std ::函数)GT; :: _无用]” |   /home/craig/work/litd/test/main.cpp:29|97 |从这里实例化|   /usr/include/c++/4.5/functional | 1713|error:无法匹配来电   “(标准:: _绑定(STD :: _占位符&LT 1为卤素;)&GT)   (STD :: shared_ptr的)” | || ===构建完成:1个错误,0个警告   === |

编辑: 更神秘的是,当我将include头更改为它们的tr1等价物时,它确实可以编译。

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

2 个答案:

答案 0 :(得分:1)

它看起来像g ++的std::functionstd::bind实现中的错误,具体取决于您是否可以使用bind(&Foo::Bar, placeholders::_1)调用foo返回的对象;如果这样做:

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

那么g ++的std::function实现似乎不完整。否则,std::bind的实现似乎不完整。

[20.8.9.1.2]函数模板bind状态:

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

...

     

返回:具有弱结果类型(20.8.2)的转发调用包装器gg(u1, u2, ..., uM)的效果应为INVOKE(fd, v1, v2, ..., vN, result_of::type)

[20.8.2]要求声明:

  

如下定义INVOKE(f, t1, t2, ..., tN)

     

- (t1.*f)(t2, ..., tN)f是指向类T的成员函数的指针时,t1T类型的对象或对T的引用类型为T的对象或对从((*t1).*f)(t2, ..., tN)派生的类型的对象的引用;

     

- fT是指向类t1的成员函数的指针时,&Foo::Bar不是上一项中描述的类型之一;

     

...

绑定u1时,返回的“转发调用包装器”将使用一个参数U1。调用其类型BoundArgs。在[20.8.9.1.2]中进一步说明,因为_1中的第一个模板参数类型是V1占位符类型,所以类型U1&&std::shared_ptr<Foo>。< / p>

应允许将bind(&Foo::Bar, placeholders::_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)); auto fn2 = bind(&Foo::Bar, placeholders::_1); fn2(foo); return 0; } 返回的转发调用包装器,因为[20.8.2]的情况2适用。

编辑:我在Windows(MinGW)上使用与您相同版本的g ++ 4.5.2。对我来说,以下编译就好了:

std::function

因此,似乎应该责怪g ++对auto fn2 = bind(&Foo::Bar, placeholders::_1); fn2(std::shared_ptr<Foo>(foo)); 的实现。

EDIT2:以下失败:

std::bind
  

SO7408263.cpp:19:31:错误:无法调用'(std :: _ Bind(std :: _ Placeholder&lt; 1&gt;)&gt;)(std :: shared_ptr)'

毕竟也许是{{1}}。

答案 1 :(得分:0)

该函数将重载->*以使用指向成员的指针。我相信shared_ptr不提供此功能。 TR1规范可能已经强制要求专业化,但C ++ 11可能没有。在Visual Studio中,C ++ 11 shared_ptr被定义为TR1版本,这可以解释其中的差异。