Пересылка выражений в списке инициализаторов
Инициализационные списки списков действительно удобны для инициализации контейнеров С++:
std::vector<int>({1, 2, 3})
... но кажется, что выражение списка инициализаторов, заключенное в фигурной скобке, подобно {1,2,3}
, будет привязываться только к функции, которая принимает std::initializer_list<int>
- она, похоже, не привязана к универсальной (пересылающей) ссылке:
template <class T>
void foo(T&& v)
{
std::vector<int>(std::forward<T>(v));
}
int main()
{
foo({1, 2, 3})
}
Выводится:
test2.cpp:11:6: note: template<class U> void foo(U&&)
test2.cpp:11:6: note: template argument deduction/substitution failed:
test2.cpp:33:13: note: couldn't deduce template parameter ‘U’
(Это был результат с GCC 4.7.2.)
К сожалению, мы не можем перенаправить выражение списка инициализаторов. Поскольку было бы очень удобно это сделать, я хотел бы спросить, почему это не работает? Почему не удается привязать выражение списка инициализаторов в скобках к ссылке пересылки? Или это разрешено, и, возможно, мой компилятор слишком стар?
Ответы
Ответ 1
Не то, чтобы он не мог привязываться к параметру вашей функции; это просто, что компилятор не может определить тип вашего шаблона. Это компилируется:
#include <vector>
template <class T>
void foo(T&& v)
{
std::vector<int>(std::forward<T>(v));
}
int main()
{
foo(std::initializer_list<int>{1, 2, 3});
}
Ответ 2
В этом случае список инициализаторов не может быть выведен. Это явно рассматривается стандартом в [temp.deduct.call]:
Вывод аргумента шаблона производится путем сравнения каждого параметра параметра шаблона функции (назовем его P
) с помощью тип соответствующего аргумента вызова (назовите его A
), как описано ниже. Если P
является зависимым типом, [...]. В противном случае аргумент списка инициализатора приводит к тому, что параметр считается не выведенным контекст (14.8.2.5). [Пример:
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
Пример здесь для g
- это именно ваш случай - T
не является зависимым типом, поэтому это считается не выведенным контекстом. Компилятор правильно отклоняет ваш код.