为什么我不能用make_pair来平局?

Why can't I use make_pair to tie?

我正在尝试模仿 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 构造函数 ab 未分配。
为什么 pair 构造函数有效但 make_pair 无效?

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 没有引用限定符的不幸副作用。在 C++≥11 中,您可以删除右值 thisoperator=(在非标准 类 中),并使此类情况成为编译器错误,而不是无声的令人惊讶的行为。

实际上你可以使用 std::make_pair。但是你需要实现reference_wrapperclass来模仿引用。示例(不是很精致,但按预期工作)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;
}

在 20.2.2[lib.pairs]8 中,标准规定 pair 使用 "explicit types" 而 make_pair 的 "types are deduced".

这就是标准为 pair:

定义构造函数的原因
template <class T1, class T2>
pair(const T1& x, const T2& y)

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

non-static reference member int& std::pair<int&, int&>::first, can't use default assignment operator

问题是 pair 使用 implicitly-declared copy assignment operator 如果 pair:

Has a non-static data member of a reference type

无论是由 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);
}

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

tie(a, b) = test();

Live Example

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