GCC according to C++11 cannot deduce the type for either first two calls to bar
. It warns because it implements an extension to C++11.
The Standard says that when a function argument in a call to a function template is a { ... }
and the parameter is not initializer_list<X>
(optionally a reference parameter), that then the parameter's type cannot be deduced by the {...}
. If the parameter is such a initializer_list<X>
, then the elements of the initializer list are deduced independently by comparing against X
, and each of the deductions of the elements have to match.
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
}
In this example, the first is OK, and the second is OK too because the first element yields type int
, and the second element compares {2}
against T
- this deduction cannot yield a constradiction since it doesn't deduce anything, hence eventually the second call takes T
as int
. The third cannot deduce T
by any element, hence is NOT OK. The last call yields contradicting deductions for two elements.
One way to make this work is to use such a type as parameter type
template <class T> void bar(std::initializer_list<std::initializer_list<T>> x) {
// ...
}
I should note that doing std::initializer_list<U>({...})
is dangerous - better remove those (...)
around the braces. In your case it happens to work by accident, but consider
std::initializer_list<int> v({1, 2, 3});
// oops, now 'v' contains dangling pointers - the backing data array is dead!
The reason is that ({1, 2, 3})
calls the copy/move constructor of initializer_list<int>
passing it a temporary initializer_list<int>
associated with the {1, 2, 3}
. That temporary object will then be destroyed and die when the initialization is finished. When that temporary object that is associated with the list dies, the backing-up array holding the data will be destroyed too (if the move is elided, it will live as long as "v"; that's bad, since it would not even behave bad guaranteedly!). By omitting the parens, v
is directly associated with the list, and the backing array data is destroyed only when v
is destroyed.