简体   繁体   English

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

[英]Using std::tr1::bind with std::vector::push_back

Why my VS2010 can't compile this code: 为什么我的VS2010无法编译此代码:

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

You should be more specific why this doesn't seem to work for you. 您应该更具体地说明为什么这似乎不适合您。

#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

Update: Luc Danton is right, the issue here is the overloaded push_back . 更新: Luc Danton是对的,这里的问题是重载的push_back See question Are there boost::bind issues with VS2010 ? 请参阅问题VS2010是否存在boost :: bind问题? . Also, note that the issue is not limited to push_back , see Visual Studio 2010 and boost::bind . 另请注意,问题不仅限于push_back ,请参阅Visual Studio 2010和boost :: bind

The bottom line is that what you're trying to do isn't possible in portable C++. 最重要的是,您在便携式 C ++中无法实现的目标。 std::vector<>::push_back is guaranteed to be overloaded in C++11 compilers, as at a minimum there must be an overload for lvalues and an overload for rvalues. std::vector<>::push_back在C ++ 11编译器中过载,因为至少必须有lvalues的重载和rvalues的重载。

Usually , when taking the address of an overloaded member function, §13.4/1 in the C++11 FDIS tells us that we can control which overload we're taking the address of thusly: 通常 ,当获取重载成员函数的地址时,C ++ 11 FDIS中的§13.4/ 1告诉我们,我们可以控制我们正在采用的地址:

A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. 在某些上下文中,使用不带参数的重载函数名称解析为函数,指向函数的指针或指向来自重载集的特定函数的成员函数的指针。 A function template name is considered to name a set of overloaded functions in such contexts. 函数模板名称被认为是在这种上下文中命名一组重载函数。 The function selected is the one whose type is identical to the function type of the target type required in the context. 选择的函数是其类型与上下文中所需的目标类型的函数类型相同的函数。 [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. [ 注意:也就是说,当匹配指向成员函数的指针类型时,忽略函数所属的类。 —end note ] The target can be - 尾注 ]目标可以

  • an object or reference being initialized, 正在初始化的对象或引用,
  • the left side of an assignment, 作业的左侧,
  • a parameter of a function, 一个函数的参数,
  • a parameter of a user-defined operator, 用户定义的运算符的参数,
  • the return value of a function, operator function, or conversion, 函数,运算符函数或转换的返回值,
  • an explicit type conversion , or 显式类型转换 ,或
  • a non-type template-parameter. 非类型模板参数。

The overloaded function name can be preceded by the & operator. 重载的函数名称可以在&运算符之后。 An overloaded function name shall not be used without arguments in contexts other than those listed. 如果没有参数,则不应在除列出的上下文之外的上下文中使用重载的函数名称。 [ Note: Any redundant set of parentheses surrounding the overloaded function name is ignored. [ 注意:忽略重载函数名称周围的任何冗余括号。 —end note ] - 尾注 ]

The problem comes from §17.6.5.5/2: 问题来自§17.6.5.5/ 2:

An implementation may declare additional non-virtual member function signatures within a class by adding arguments with default values to a member function signature; 实现可以通过向成员函数签名添加具有默认值的参数来在类中声明其他非虚拟成员函数签名; hence, the address of a member function of a class in the C++ standard library has an unspecified type. 因此,C ++标准库中类的成员函数的地址具有未指定的类型。

Consequently, it is not portable to ever take the address of a standard library class member function, as the type of such an expression is by definition unknowable except on an implementation-by-implementation basis. 因此,永远不能获取标准库类成员函数的地址,因为这样的表达式的类型根据定义是不可知的,除了在逐个实现的基础上。

Luc Danton's proposed workaround (specifically, using a lambda) is also what I would recommend: Luc Danton建议的解决方法(特别是使用lambda)也是我推荐的:

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

Try this: 尝试这个:

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)();

With C++03 note that push_back cannot be a local type; 用C ++ 03注意push_back不能是本地类型; with C++11 it can but it would be more idiomatic (and completely equivalent) to use a lambda. 使用C ++ 11它可以但是使用lambda会更加惯用(并且完全等效)。

In all likeliness your implementation provides overloads for std::vector<T>::push_back and thus its address would have to be disambiguated. 在所有可能性中,您的实现为std::vector<T>::push_back提供重载,因此必须消除其地址的歧义。 If this is what happened, your compiler should have provided you with an appropriate error message. 如果发生这种情况,您的编译器应该已经为您提供了相应的错误消息。 In all cases, you should explain what you mean by "it's not possible". 所有情况下,你应该通过“它不可能”来解释你的意思。


The point is not to use such helper functions. 关键是不要使用这样的辅助函数。 – magenta - 洋红色

Then why didn't you put it in the question? 那你为什么不把它放在这个问题上呢? I can't read your mind. 我无法理解你的想法。

You can also try this: 你也可以试试这个:

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)();

Which I believe is not guaranteed to success. 我认为不能保证成功。

It should propably lok like this: 它应该像这样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM