为什么我不能使用make_pair来绑?

时间:2016-09-28 10:59:44

标签: c++ c++11 reference c++03 std-pair

我试图模仿tie预C ++ 11的行为。

pair<int, int> test() {
    return make_pair(13, 42);
}

int main() {
    int a = 1, b = 2;

    pair<int&, int&>(a, b) = test();

    cout << a << ' ' << b << endl;
}

This works但是,如果我使用make_pair代替pair构造函数a并且未分配b
为什么pair构造函数有效但不是make_pair

3 个答案:

答案 0 :(得分:3)

实际上你可以使用std::make_pair。但是你需要实现reference_wrapper类来模仿参考。示例(非常精细,但按预期工作)c ++ 03方法:

#include <iostream>
#include <utility>

using namespace std;

template <class T>
struct reference_wrapper {
   bool is_const;
   T* v;
   T const* cv;
   reference_wrapper(T& t): v(&t), is_const(false) { }
   reference_wrapper(T const& t): cv(&t), is_const(true) { }

   reference_wrapper &operator=(reference_wrapper const &rw) {
      if (rw.is_const) {
         *v = *rw.cv;
      } else {
         *v = *rw.v;
      }
   }
};

template <class T>
reference_wrapper<T> ref(T &t) {
   return reference_wrapper<T>(t);
}

pair<int, int> test() {
    return make_pair(13, 42);
}

int main() {
    int a = 1, b = 2;

    //pair<int&, int&>(a, b) = test();  // works
    make_pair(ref(a), ref(b)) = test(); // now it does work

    std::cout << a << ' ' << b << std::endl;
}

答案 1 :(得分:3)

在20.2.2 [lib.pairs] 8中,标准规定pair使用&#34;显式类型&#34;而make_pair&#34; s&#34;类型被推断出来&#34;。

这就是标准为pair定义构造函数的原因:

template <class T1, class T2>
pair(const T1& x, const T2& y)

如果您在C++03 compiler上运行代码,则会收到此错误:

  

非静态引用成员int& std::pair<int&, int&>::first,不能使用默认赋值运算符

问题在于,pair使用的implicitly-declared copy assignment operator如果pair

未定义
  

具有引用类型的非静态数据成员

无论是由make_pair还是pair构造函数定义,模板参数都会将pair的成员定义为int&,因此隐式声明不会定义复制赋值运算符。 因此,使用C ++ 03中的pair无法实现这一点。

如果不希望使用return参数,您可以编写自己的tie实现:

template <class T1, class T2>
struct tie{
    T1& first;
    T2& second;

    tie(T1& x, T2& y) : first(x), second(y) {}

    tie<T1, T2>& operator=(const pair<T1, T2>& rhs){
        first = rhs.first;
        second = rhs.second;

        return *this;
    }
};

这将允许分配pair

tie<int, int>(a, b) = test();

要获得不需要模板参数的确切C ++ 11行为,您需要定义一个函数。如果tie嵌套在namespace details中,则该函数可以定义为:

template <class T1, class T2>
details::tie<T1, T2> tie(T1& x, T2& y) { 
    return details::tie<T1, T2>(x, y);
}

这将允许分配pair,就像在C ++ 11中一样:

tie(a, b) = test();

Live Example

请注意,这仍然不能容忍使用int&模板参数,因此details::tie<int&, int&>tie<int&, int&>将会像以前一样失败。

答案 2 :(得分:2)

make_pair生成一对值,而不是引用。这意味着它会在您的示例中生成pair<int, int>,并且您将test()的结果分配给临时变量¹。

您可以使用以下内容模仿tie

template<typename T, typename U>
std::pair<T&, U&> tie_pair(T& l, U& r)
{
    return std::pair<T&, U&>(l, r);
}

http://ideone.com/muAcaG

¹这是C ++ 03不具备ref-qualifiers的不幸副作用。在C ++≥11中,您可以删除operator=的rvalue this(在非std类中)并使这种情况成为编译器错误而不是无声的惊人行为。