Это не так, как std::make_pair
предназначен для использования; Вы не должны явно указывать аргументы шаблона.
C ++ 11 std::make_pair
принимает два аргумента, типа T&&
и U&&
, где T
и U
- параметры типа шаблона. Фактически это выглядит так (без учета типа возвращаемого значения):
template <typename T, typename U>
[return type] make_pair(T&& argT, U&& argU);
Когда вы вызываете std::make_pair
и явно указываете аргументы типа шаблона, вычитание аргументов не происходит. Вместо этого аргументы типа подставляются непосредственно в объявление шаблона, что приводит к:
[return type] make_pair(std::string&& argT, int&& argU);
Обратите внимание, что оба эти типа параметров являются ссылками rvalue. Таким образом, они могут привязываться только к значениям. Это не проблема для второго передаваемого аргумента, 7
, потому что это выражение rvalue. s
, однако, является выражением lvalue (оно не является временным и не перемещается). Это означает, что шаблон функции не соответствует вашим аргументам, поэтому вы получаете ошибку.
Итак, почему это работает, если вы явно не указываете, что T
и U
находятся в списке аргументов шаблона? Вкратце, ссылочные параметры rvalue являются специальными в шаблонах. Отчасти благодаря языковой функции, называемой свертывание ссылок , ссылочный параметр rvalue типа A&&
, где A
- это параметр типа шаблона, может связываться с любым видом A
.
Не имеет значения, является ли A
lvalue, rvalue, const-квалифицированным, volatile-квалифицированным или неквалифицированным, A&&
может связываться с этим объектом (опять же, если и только если A
сам является параметром шаблона).
В вашем примере мы делаем звонок:
make_pair(s, 7)
Здесь s
- это значение типа std::string
, а 7
- это значение типа int
. Поскольку вы не указываете аргументы шаблона для шаблона функции, для определения аргументов используется вывод аргумента шаблона.
Чтобы связать s
, lvalue, с T&&
, компилятор выводит T
в std::string&
, получая аргумент типа std::string& &&
. Тем не менее, нет никаких ссылок на ссылки, поэтому эта «двойная ссылка» сворачивается и становится std::string&
. s
соответствует.
Просто связать 7
с U&&
: компилятор может вывести U
в int
, что дает параметр типа int&&
, который успешно связывается с 7
, потому что это значение.
Есть много тонкостей с этими новыми языковыми функциями, но если вы следуете одному простому правилу, это довольно просто:
Если аргумент шаблона может быть выведен из аргументов функции, пусть он будет выведен. Не указывайте явно аргумент, если вам это абсолютно не нужно.
Пусть компилятор выполнит тяжелую работу, и в любом случае 99,9% времени это будет именно то, что вы хотели. Если это не то, что вам нужно, вы обычно получаете ошибку компиляции, которую легко идентифицировать и исправить.