0

使用 std::bind 时,我能够通过传递指针或迭代器而不是对象本身来绑定 VS2010 中的数据成员。但是,它似乎不再适用于 VS2012:

#include <vector>
#include <utility>
#include <iostream>
#include <functional>

using namespace std;

int main()
{
    vector<pair<string, int>> v; 
    v.push_back(make_pair("abc", 10));
    auto f = bind(&pair<string, int>::second, v.begin());
    int res = f();
    cout << res << endl;
    return 0;
}

( http://ideone.com/n1KWu )

GCC 也可以很好地编译和运行这段代码,但是 VS2012 给了我一个错误:

error C2440: 'initializing' : cannot convert from 'std::_Do_call_ret<_Forced,_Ret,_Funx,_Btuple,_Ftuple>::type' to 'int'
1>          with
1>          [
1>              _Forced=false,
1>              _Ret=void,
1>              _Funx=std::_Pmd_wrap<int std::pair<std::string,int>::* ,int,std::pair<std::string,int>>,
1>              _Btuple=std::tuple<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<std::pair<std::string,int>>>>>,
1>              _Ftuple=std::tuple<>
1>          ]
1>          Expressions of type void cannot be converted to other types

请注意,如果我传递一个 std::pair 实例而不是迭代器或指向它的指针,那么 VS2012 很高兴。

这里有什么问题?

4

2 回答 2

1

std::mem_fn(和std::bind)根据设施规定和实施INVOKE,见§20.8.10 [func.memfn] p1

返回:一个简单的调用包装器 (20.8.1) fn,使得表达式fn(t, a2, ..., aN)等价于INVOKE(pm, t, a2, ..., aN)(20.8.2)。

因此,这很可能是 MSVC 实现中的一个错误INVOKE,特别是第四个要求:

§20.8.2 [func.require] p1

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

  • (t1.*f)(t2, ..., tN)whenf是指向类的成员函数的指针,T并且t1是类型对象T或对类型对象的T引用或对派生于的类型对象的引用T
  • ((*t1).*f)(t2, ..., tN)whenf是指向类的成员函数的指针,T并且t1不是上一项中描述的类型之一;
  • t1.*fwhenN == 1f是指向类的成员数据的指针,T并且t1是类型对象T或对类型对象的T引用或对派生于的类型对象的引用T
  • (*t1).*fwhenN == 1和 f 是指向类的成员数据的指针,T 并且t1不是上一项中描述的类型之一
  • f(t1, t2, ..., tN)在所有其他情况下。

粗体部分基本上表示当f是成员指针(任何类型)并且t1不是引用时,尝试取消引用它并在此之后应用成员指针。这应该是您的代码的情况,因为迭代器不是对T. GCC 正确地实现了这一点。

我建议在 MS Connect 上提交错误报告。

于 2012-10-24T00:27:27.517 回答
0

如果您检查这样的参考资料您会看到第一个参数应该是

将绑定到某些参数的函数对象

换句话说,您不应该能够绑定数据成员或变量,只能绑定函数和类似函数的对象。

引用 C++11 标准(第 20.8.9 节):

函数模板 bind 返回一个对象,该对象将作为参数传递的可调用对象绑定到其他参数。

于 2012-10-19T06:12:32.617 回答