Конечная запятая в равномерной инициализации

Есть ли какая-либо потенциальная смысловая разница, когда я использую конечную запятую во время равномерной инициализации?

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

Можно ли использовать конечную запятую, чтобы компилятор мог выбрать конструктор std::vector::vector(std::initializer_list< std::size_t >) вместо std::vector::vector(std::size_t, const std::size_t &) или есть ли какие-либо другие трюки с указанным синтаксисом?

Могу ли я использовать его для обнаружения, существует ли перегрузка std::initializer_list -структора?

Учитывая следующий код, какой конструктор должен быть выбран?

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

Этот код принят gcc 8 и A(int) выбран в обоих случаях.

Ответы

Ответ 1

Во-первых, правила грамматики С++ делают конечный , необязательный для braced-init-list. Чтобы процитировать dcl.init/1

Декларатор может указать начальное значение для идентификатора, являющегося объявлен. Идентификатор обозначает инициализацию переменной. процесс инициализации, описанный в остальной части [dcl.init] применяется также к инициализациям, указанным в других синтаксических контекстах, таких как инициализация функциональных параметров ([expr.call]) или инициализация возвращаемых значений ([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 }
  { }

Во-вторых, вы не можете в значительной степени переопределить систему разрешения перегрузки. Он всегда будет использовать конструктор std::initializer_list, если вы используете такой синтаксис, и такой конструктор std::initializer_list доступен.

dcl.init.list/2:

Конструктор - это конструктор списка инициализаторов, если его первый параметр имеет тип std:: initializer_list или ссылка на возможно, cv-квалифицированный std:: initializer_list для некоторого типа E, и либо других параметров нет, либо все остальные параметры аргументы по умолчанию. [Примечание. Конструкторы списка инициализаторов предпочтительнее других конструкторов в инициализации списка ([over.match.list])....


Программа ниже печатает 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};
}

Несмотря на то, что 5 является литералом типа int, должно было иметь смысл выбрать единственный конструктор аргументов, поскольку он идеально подходит; и конструктор std::initializer_list<double> хочет список double. Однако правила предпочитают std::initializer_list<double>, потому что это его конструктор-инициализатор.

В результате даже программа ниже терпит неудачу из-за сужения конверсии:

#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};
}

В ответ на ваш комментарий ниже, "что, если нет перегрузки с std:: initializer_list, или это не первый параметр конструктора?" - тогда разрешение перегрузки не выбирает его. Демо-ролик:

#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};
}

Печать

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

Если нет конструктора-списка инициализаторов, то инициализатор {initializer-list...,} в значительной степени возвращается к прямой инициализации в соответствии с dcl.init/16, чья семантика охвачена следующим абзацем dcl.init/16

Ответ 2

Нет. Эта запятая - это уступка, чтобы заставить макропроцессоры препроцессора работать без ошибок компиляции. Это ничего не значит о вашем типе данных или его размере.