GCC según C++ 11 no se puede deducir el tipo de las dos primeras llamadas a bar
. Advierte porque implementa una extensión de a C++ 11.
La norma dice que cuando un argumento de función en una llamada a una plantilla de función es una { ... }
y el parámetro no es initializer_list<X>
(opcionalmente un parámetro de referencia), que a continuación, el tipo del parámetro no se puede deducir por el {...}
. Si el parámetro es tal como initializer_list<X>
, los elementos de la lista de inicializadores se deducen de forma independiente comparando con X
, y cada una de las deducciones de los elementos debe coincidir.
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
}
En este ejemplo, la primera es OK, y el segundo es bien también porque los primeros rendimientos elemento de tipo int
, y el segundo elemento compara {2}
contra T
- esta deducción no puede producir un constradiction ya que no hace deduce cualquier cosa, por lo tanto, finalmente, la segunda llamada toma T
como int
. El tercero no puede deducir T
por ningún elemento, por lo tanto, NO ES ACEPTABLE. La última llamada produce deducciones contradictorias para dos elementos.
Una manera de hacer este trabajo es utilizar un tipo como el tipo de parámetro
template <class T> void bar(std::initializer_list<std::initializer_list<T>> x) {
// ...
}
Debo señalar que haciendo std::initializer_list<U>({...})
es peligroso - mejor eliminar los (...)
alrededor de los tirantes. En el caso de que suceda a trabajar por accidente, pero tenga en cuenta
std::initializer_list<int> v({1, 2, 3});
// oops, now 'v' contains dangling pointers - the backing data array is dead!
La razón es que ({1, 2, 3})
llama al constructor de copia/movimiento de initializer_list<int>
pasándole un temporal initializer_list<int>
asociado con el {1, 2, 3}
. Ese objeto temporal se destruirá y morirá cuando finalice la inicialización. Cuando ese objeto temporal que está asociado con la lista muera, la matriz de respaldo que contiene los datos también se destruirá (si se elimina el movimiento, vivirá tanto tiempo como "v"; eso es malo, ya que ni siquiera se comportaría) mal garantizado!). Al omitir los parens, v
está directamente asociado con la lista, y los datos de la matriz de respaldo se destruyen solo cuando se destruye v
.
posible duplicado de [¿Por qué mi plantilla no acepta una lista de inicializadores] (http://stackoverflow.com/questions/4757614/why-doesnt-my-template-accept-an-initializer-list) - Esa pregunta es básicamente un duplicado. El hecho de que la deducción del tipo se haga en absoluto en una lista de inicializadores es una extensión de g ++. – Omnifarious
@Omnifarious no estoy seguro si estos son engañados. Mi pregunta tenía por objeto solicitar menos detalles que aparentemente esta pregunta. –