При использовании 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;
}
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 будет счастлив.
В чем здесь проблема?
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)
когдаf
указатель на функцию-член классаT
а такжеt1
является объектом типаT
или ссылка на объект типаT
или ссылка на объект типа, производного отT
;((*t1).*f)(t2, ..., tN)
когдаf
указатель на функцию-член классаT
а такжеt1
не является одним из типов, описанных в предыдущем пункте;t1.*f
когдаN == 1
а такжеf
указатель на данные члена классаT
а такжеt1
является объектом типаT
или ссылка на объект типаT
или ссылка на объект типа, производного отT
;(*t1).*f
когдаN == 1
и f — указатель на данные члена классаT
а такжеt1
не является одним из типов, описанных в предыдущем пункте;f(t1, t2, ..., tN)
во всех остальных случаях.
Жирная часть в основном говорит, что когда f
указатель члена (любого типа) и t1
не является ссылкой, попробуйте разыменовать его и после этого применить указатель на член. Это должно иметь место для вашего кода, так как итератор не является ссылкой на T
, GCC реализует это правильно.
Если вы проверите ссылку как это вы увидите, что первые аргументы должны быть
функциональный объект, который будет связан с некоторыми аргументами
Другими словами, вы не должны иметь возможность связывать элементы данных или переменные, только функции и функционально-подобные объекты.
Чтобы процитировать из стандарта C ++ 11 (раздел 20.8.9):
Функция template bind возвращает объект, который связывает вызываемый объект, переданный в качестве аргумента, с дополнительными аргументами.