22

这到底是怎么回事?
我正在尝试创建一对 anint和 astring如果我使用“魔术值”但似乎无法传递变量,我可以创建这对。

std::vector<std::pair<int, std::string> > num_text;

std::string text = "Smeg";
int num = 42;

// Works fine
num_text.push_back(std::make_pair<int, std::string>(42, std::string("Smeg")));  

// Cannot convert parameter 2 from 'std::string' to 'std::string &&'
num_text.push_back(std::make_pair<int, std::string>(42, text));

// Cannot convert parameter 1 from 'int' to 'int &&'
num_text.push_back(std::make_pair<int, std::string>(num, std::string("Smeg")));

// Cannot convert parameter 1 from 'int' to 'int &&'
num_text.push_back(std::make_pair<int, std::string>(num, text));

// Works fine again
num_text.push_back(std::make_pair<int, std::string>(42, std::string("Smeg")));

我正在使用 VS 2012 并粘贴了一些用 VS 2008 编写的代码。无法想象这与它有什么关系,但原始 (2008) 代码没有问题。

对于无法锻炼这里发生的事情,我有点愚蠢,但我能说什么,我就是不明白。

4

4 回答 4

26

参考说:

template< class T1, class T2 >
std::pair<T1,T2> make_pair( T1 t, T2 u );           (until C++11)

template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );       (since C++11)

请注意,返回类型不同。它还说:

推导的类型 V1 和 V2 是 std::decay::type 和 std::decay::type (应用于按值传递的函数的参数的常用类型转换)除非应用 std::decay 导致 std::reference_wrapper 为某些类型 X,在这种情况下推导的类型是 X&。

所以事实上,从 2008 年开始(我的意思是 Visual C++ 2008),函数的语义make_pair已经发生了变化。您可以从中删除模板参数std::make_pair并让它推断类型,或者std::pair如果您需要对特定类型进行配对,则可以使用 's 构造函数:

num_text.push_back(std::make_pair(num, text));               // deduced type
num_text.push_back(std::pair<int, std::string>(num, text));  // specific type

编译错误的原因是您已将类型指定为int(as T1) 和std::string(as T2),因此函数需要T1 &&and T2 &&。请参阅此答案以了解为什么会出现问题。

于 2013-10-14T10:40:39.403 回答
17

make_pair<T1,T2>不会产生一对 type pair<T1,T2>,而是从其参数中推导出一对合适的引用类型以允许完美转发。它被指定为

template <class T1, class T2>
pair<V1, V2> make_pair(T1&& x, T2&& y);

对于一些合适的引用类型V1V2. 这仅在推导参数类型时才有效,因此可以在必要时&&衰减为左值引用。通过显式指定模板参数,它们不再被推导,因此函数参数只能是rvalues

解决方案是让编译器推断类型:

num_text.push_back(std::make_pair(42, std::string("Smeg")));  // Works fine
num_text.push_back(std::make_pair(42, text));                 // Works fine
num_text.push_back(std::make_pair(num, std::string("Smeg"))); // Works fine
num_text.push_back(std::make_pair(num, text));                // Works fine
num_text.push_back(std::make_pair(42, std::string("Smeg")));  // Works fine again

如果您需要制作一对特定类型,请不要使用make_pair,只需制作一对

// Works, but perhaps with more copying than you want.
num_text.push_back(std::pair<int, std::string>(num, text));   
于 2013-10-14T10:44:44.333 回答
6

make_pair通常在明确指定模板参数的情况下使用。这就是它的用途:

num_text.push_back(std::make_pair(42, std::string("Smeg")));
num_text.push_back(std::make_pair(42, text));
num_text.push_back(std::make_pair(num, std::string("Smeg")));
num_text.push_back(std::make_pair(num, text));
num_text.push_back(std::make_pair(42, std::string("Smeg")));

或者,如果您想要确切的类型:

typedef decltype(num_text)::value_type value_type;
num_text.push_back(value_type(42, std::string("Smeg")));
num_text.push_back(value_type(42, text));
num_text.push_back(value_type(num, std::string("Smeg")));
num_text.push_back(value_type(num, text));
num_text.push_back(value_type(42, std::string("Smeg")));
于 2013-10-14T10:42:37.560 回答
2

现在std::make_pair在 C++ 标准中定义如下

template <class T1, class T2>

见下文make_pair(**T1&&, T2&&**);

您可以在不使用的情况下编写更简单的std::make_pair

num_text.push_back( { 42, text } );.

于 2013-10-14T10:46:15.193 回答