Weird ошибка компилятора: невозможно преобразовать параметр из 'int' в 'int &&'
Что здесь происходит?
Я пытаюсь создать пару int
и string
, и я могу создать пару, если я использую "магические значения", но не могу передать переменные.
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) не было проблем.
Я немного чувствую себя немного глупым, потому что не способен тренироваться, что здесь происходит, но что я могу сказать, я просто не понимаю.
Ответы
Ответ 1
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)
Обратите внимание, что тип возврата отличается. В нем также говорится:
Выведенные типы V1 и V2 являются std:: decay:: type и std:: decay:: type (обычные преобразования типов, применяемые к аргументам функций, переданных по значению), если приложение std:: decay не приводит к std:: reference_wrapper для некоторого типа X, и в этом случае выводимый тип - X &.
Итак, с 2008 года (я имею в виду Visual С++ 2008) семантика функции make_pair
изменилась. Вы можете либо удалить параметры шаблона из std::make_pair
, либо вывести его тип, либо использовать конструктор std::pair
, если вам нужно создать пары определенного типа:
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 &&
, См. этот ответ, почему эта проблема.
Ответ 2
make_pair<T1,T2>
не создает пару типа pair<T1,T2>
, а выводит из своих аргументов подходящую пару ссылочных типов, чтобы обеспечить идеальную пересылку. Он указан как
template <class T1, class T2>
pair<V1, V2> make_pair(T1&& x, T2&& y);
для некоторых подходящих ссылочных типов V1
и V2
. Это работает только в том случае, если типы аргументов выводятся, поэтому &&
может при необходимости распадаться на ссылку lvalue. Явным образом задавая параметры шаблона, они больше не выводятся, поэтому аргументы функции могут быть только значениями.
Решение состоит в том, чтобы позволить компилятору вывести типы:
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));
Ответ 3
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")));
Ответ 4
Теперь std::make_pair
определяется в стандарте С++
template <class T1, class T2>
см. ниже make_pair(**T1&&, T2&&**);
Вы можете написать проще, не используя std::make_pair
num_text.push_back( { 42, text } );
.