2013-10-14 4 views
12

Что здесь происходит?
Я пытаюсь создать пару int и string, и я могу создать пару, если я использую «магические значения», но не могу передать переменные.Weird ошибка компилятора: невозможно преобразовать параметр из 'int' в 'int &&'

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) код.

Я чувствую себя немного глупым, потому что не могу тренироваться, что здесь происходит, но что я могу сказать, я просто не понимаю.

ответ

14

Reference говорит:

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) 

Обратите внимание, что возвращаемый тип отличается. Он также говорит:

The deduced types V1 and V2 are std::decay::type and std::decay::type (the usual type transformations applied to arguments of functions passed by value) unless application of std::decay results in std::reference_wrapper for some type X, in which case the deduced type is 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 (как T1) и std::string (как T2), и поэтому функция ожидает T1 && и T2 &&. См. this answer, почему это проблема.

+0

Или передать копию построенных времен. Например, 'num_text.push_back (std :: make_pair (42, std :: string (text))) Или опустить параметры шаблона. –

+0

@NikosC., Опустите параметры, конечно, но ваше первое решение не будет. Я бы не отправил '42' вместо' num'! – Shahbaz

+0

Как я уже говорил, копия построена временными. Для передачи 'num' вы можете использовать' num_text.push_back (std :: make_pair (int (num), std :: string (text))). –

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"))); 
14

make_pair<T1,T2> не делает пару типа pair<T1,T2>, а дедуцирует подходящую пару ссылочные типы из своих аргументов, чтобы обеспечить идеальную пересылку. Это определяется как

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

для некоторых подходящих ссылочных типов V1 и V2. Это работает только при выводе типов аргументов, так что && может затухать до lvalue, если необходимо. Явным образом задавая параметры шаблона, они больше не выводятся, поэтому аргументы функции могут быть только 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)); 
2

Теперь std::make_pair определяется следующим образом в C++ Standard

template <class T1, class T2> 

смотри ниже make_pair(**T1&&, T2&&**);

Вы могли бы написать проще без использования std::make_pair

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

Смежные вопросы