使用std :: tr1 :: bind与std :: vector :: push_back

时间:2011-05-15 09:25:46

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

为什么我的VS2010无法编译此代码:

#include <functional>
#include <vector>
int main()
{
    std::vector<int> vec;
    std::bind(&std::vector<int>::push_back, std::ref(vec), 1)();
    return 0;
}

4 个答案:

答案 0 :(得分:5)

你应该更具体地说明为什么这似乎不适合你。

#include <iostream>
#include <tr1/functional>
#include <vector>

int main(int argc, char* argv[]) {
    std::vector<int> vec;
    std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), 1)();
    std::cout << "vec.size = " << vec.size() << std::endl;
    std::cout << "vec[0] = " << vec[0] << std::endl;
    return 0;
}

$ gcc -o test -lstdc++ test.cpp && ./test
vec.size = 1
vec[0] = 1

更新: Luc Danton是对的,这里的问题是重载的push_back。请参阅问题Are there boost::bind issues with VS2010 ?。另请注意,问题不仅限于push_back,请参阅Visual Studio 2010 and boost::bind

答案 1 :(得分:4)

最重要的是,您在 portable C ++中无法实现的目标。保证{C> 11编译器中的std::vector<>::push_back会被重载,因为至少必须有左值的重载和rvalues的重载。

通常,当获取重载成员函数的地址时,C ++ 11 FDIS中的§13.4/ 1告诉我们,我们可以控制我们正在采用的地址:

  

使用不带参数的重载函数名称会在某些上下文中解析为函数,指向函数的指针或指向过载集中特定函数的成员函数的指针。函数模板名称被认为是在这种上下文中命名一组重载函数。 选择的函数是其类型与上下文中所需的目标类型的函数类型相同的函数。 [注意:即,函数所在的类匹配指向成员函数的指针时忽略成员。 -end note ]目标可以是

     
      
  • 正在初始化的对象或引用,
  •   
  • 作业的左侧,
  •   
  • 函数的参数
  •   
  • 用户定义的运算符的参数
  •   
  • 函数,运算符函数或转换的返回值
  •   
  • 显式类型转换
  •   
  • 非类型模板参数。
  •   
     

重载的函数名称可以在&运算符之后。如果没有参数,则不应在除列出的上下文之外的上下文中使用重载的函数名称。 [注意:忽略重载函数名称周围的任何冗余括号。 -end note ]

问题来自§17.6.5.5/ 2:

  

实现可以通过向成员函数签名添加具有默认值的参数来在类中声明其他非虚拟成员函数签名; 因此,C ++标准库中类的成员函数的地址具有未指定的类型。

因此,使用标准库类成员函数的地址是不可移植的,因为这样的表达式的类型根据定义是不可知的,除非在逐个实现的基础上。

Luc Danton建议的解决方法(特别是使用lambda)也是我的建议:

std::vector<int> vec;
[&](){ vec.push_back(1); }();

答案 2 :(得分:3)

试试这个:

struct push_back {
    void
    operator()(std::vector<int>& vector, int i) const
    {
        vector.push_back(i);
    }
};

// somewhere else:
std::vector<int> vec;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();

使用C ++ 03注意push_back不能是本地类型;使用C ++ 11它可以,但使用lambda会更加惯用(并且完全等效)。

在所有可能性中,您的实现为std::vector<T>::push_back提供了重载,因此其地址必须消除歧义。如果发生这种情况,您的编译器应该已经为您提供了相应的错误消息。在所有案例中,你应该用“不可能”来解释你的意思。


  

关键是不要使用这样的助手   功能。 - 洋红色

那你为什么不把它放在这个问题上呢?我无法理解你的想法。

你也可以试试这个:

std::vector<int> vec;
void (std::vector<int>::*push_back)(int const&) = &std::vector<int>::push_back;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();

我相信并不能保证成功。

答案 3 :(得分:0)

应该看起来像这样:

std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), _1)(1);