为什么我不能用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
构造函数 a
和 b
未分配。
为什么 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);
}
¹ 这是 C++03 没有引用限定符的不幸副作用。在 C++≥11 中,您可以删除右值 this
的 operator=
(在非标准 类 中),并使此类情况成为编译器错误,而不是无声的令人惊讶的行为。
实际上你可以使用 std::make_pair
。但是你需要实现reference_wrapper
class来模仿引用。示例(不是很精致,但按预期工作)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();
请注意,这仍然不能容忍使用 int&
模板参数,因此 details::tie<int&, int&>
和 tie<int&, int&>
将像以前一样失败。
我正在尝试模仿 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
无效?
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);
}
¹ 这是 C++03 没有引用限定符的不幸副作用。在 C++≥11 中,您可以删除右值 this
的 operator=
(在非标准 类 中),并使此类情况成为编译器错误,而不是无声的令人惊讶的行为。
实际上你可以使用 std::make_pair
。但是你需要实现reference_wrapper
class来模仿引用。示例(不是很精致,但按预期工作)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();
请注意,这仍然不能容忍使用 int&
模板参数,因此 details::tie<int&, int&>
和 tie<int&, int&>
将像以前一样失败。