Ответ 1
GCC в соответствии с С++ 11 не может выводить тип для первых двух вызовов bar
. Он предупреждает, что он реализует расширение для С++ 11.
В стандарте говорится, что когда аргумент функции при вызове шаблона функции является { ... }
, а параметр не является initializer_list<X>
(необязательно ссылочным параметром), то тогда тип параметра не может быть выведен значением {...}
. Если параметр такой initializer_list<X>
, то элементы списка инициализаторов выводятся независимо путем сравнения с X
, и каждый из вычетов элементов должен соответствовать.
template<typename T>
void f(initializer_list<T>);
int main() {
f({1, 2}); // OK
f({1, {2}}); // OK
f({{1}, {2}}); // NOT OK
f({1, 2.0}); // NOT OK
}
В этом примере первое в порядке, а второе - тоже ОК, потому что первый элемент дает тип int
, а второй элемент сравнивает {2}
с T
- этот вывод не может привести к сглаживанию, так как он вывести что-либо, следовательно, второй вызов принимает T
как int
. Третий не может вывести T
любым элементом, следовательно, НЕ ОК. Последний вызов дает противоречивые выводы для двух элементов.
Один из способов сделать эту работу - использовать такой тип, как тип параметра
template <class T> void bar(std::initializer_list<std::initializer_list<T>> x) {
// ...
}
Я должен заметить, что делать std::initializer_list<U>({...})
опасно - лучше удалите те (...)
вокруг фигурных скобок. В вашем случае это происходит случайно, но рассмотрите
std::initializer_list<int> v({1, 2, 3});
// oops, now 'v' contains dangling pointers - the backing data array is dead!
Причина в том, что ({1, 2, 3})
вызывает конструктор copy/move initializer_list<int>
, передавая ему временный initializer_list<int>
, связанный с {1, 2, 3}
. Затем этот временный объект будет уничтожен и погибнет при завершении инициализации. Когда этот временный объект, связанный с этим списком, умирает, резервный массив, содержащий данные, также будет уничтожен (если движение будет отменено, оно будет жить до тех пор, пока "v" - это плохо, поскольку оно даже не будет вести себя плохой гарантированно!). Отпуская параны, v
напрямую связан с этим списком, а данные массива базы данных уничтожаются только тогда, когда v
уничтожается.