c++ c++14 language-lawyer c++17 uniform-initialization

c++ - Coma que se arrastra en la inicialización uniforme



c++14 language-lawyer (2)

¿Hay alguna diferencia semántica potencial cuando uso una coma al final durante la inicialización uniforme?

std::vector< std::size_t > v1{5, }; // allowed syntax std::vector< std::size_t > v2{10};

¿Puedo usar una coma final para hacer que el compilador seleccione el constructor std::vector::vector(std::initializer_list< std::size_t >) lugar de std::vector::vector(std::size_t, const std::size_t &) O hay otros trucos con la sintaxis mencionada?

¿Puedo usarlo para detectar si hay una sobrecarga std::initializer_list -constructor?

Teniendo en cuenta el siguiente código, ¿qué constructor debe seleccionarse?

struct A { A(int) { ; } A(double, int = 3) { ; } }; A a{1}; A b{2, };

Este código es aceptado por gcc 8 y A(int) está seleccionado en ambos casos.


No. Esa coma es una concesión para hacer que los trucos de macros del preprocesador funcionen sin errores de compilación. No significa nada sobre su tipo de datos o su tamaño.


Primero, las reglas gramaticales de C ++ hacen que el final , opcional para braced-init-list . Para citar dcl.init/1

Un declarador puede especificar un valor inicial para el identificador que se está declarando. El identificador designa una variable que se está inicializando. El proceso de inicialización descrito en el resto de [dcl.init] se aplica también a las inicializaciones especificadas por otros contextos sintácticos, como la inicialización de los parámetros de función ([expr.call]) o la inicialización de valores de retorno ([stmt.return] ).

initializer: brace-or-equal-initializer ( expression-list ) brace-or-equal-initializer: = initializer-clause braced-init-list initializer-clause: assignment-expression braced-init-list braced-init-list: { initializer-list ,opt } { designated-initializer-list ,opt } { }

En segundo lugar, no se puede anular el sistema de resolución de sobrecarga. Siempre utilizará el constructor std::initializer_list si usa dicha sintaxis y dicho constructor std::initializer_list está disponible.

dcl.init.list/2 :

Un constructor es un constructor de lista de inicializadores si su primer parámetro es de tipo std :: initializer_list o referencia a std :: initializer_list posiblemente calificado para cv para algún tipo E, y no hay otros parámetros o cualquier otro Los parámetros tienen argumentos por defecto. [Nota: los constructores de lista de inicializadores se favorecen sobre otros constructores en list-initialization ([over.match.list]) ...

El siguiente programa se imprime Using InitList :

#include <iostream> #include <initializer_list> struct X{ X(std::initializer_list<double>){ std::cout << "Using InitList/n"; } X(int){ std::cout << "Using Single Arg ctor/n"; } }; int main(){ X x{5}; }

A pesar del hecho de que 5 es un literal de tipo int , debería haber tenido sentido seleccionar el constructor de un solo argumento, ya que es una coincidencia perfecta; y el constructor std::initializer_list<double> quiere una lista de double . Sin embargo, las reglas favorecen std::initializer_list<double> porque es un constructor de lista de inicializadores .

Como resultado, incluso el programa siguiente falla debido a la reducción de la conversión:

#include <iostream> #include <initializer_list> struct Y{ Y(std::initializer_list<char>){ std::cout << "Y Using InitList/n"; } Y(int, int=4){ std::cout << "Y Using Double Arg ctor/n"; } }; int main(){ Y y1{4777}; Y y2{577,}; Y y3{57,7777}; }

En respuesta a su comentario a continuación, " ¿qué pasa si no hay una sobrecarga con std :: initializer_list, o no es el primer parámetro del constructor? ", Entonces la resolución de sobrecarga no lo elige. Manifestación:

#include <iostream> #include <initializer_list> struct Y{ Y(int, std::initializer_list<double>){ std::cout << "Y Using InitList/n"; } Y(int, int=4){ std::cout << "Y Using Double Arg ctor/n"; } }; int main(){ Y y1{4}; Y y2{5,}; Y y3{5,7}; }

Huellas dactilares:

Y Using Double Arg ctor Y Using Double Arg ctor Y Using Double Arg ctor

Si no hay un constructor de lista de inicializadores disponible, entonces el {initializer-list...,} prácticamente retrocede a la inicialización directa según dcl.init/16 , cuya semántica está cubierta por el párrafo de procedimiento de dcl.init/16