В чем разница между 0, int () и int {}?

Как int() а также int{} являются постоянная выражения значения равны 0Я думал, что они эквивалентны и взаимозаменяемы, поэтому компиляторы должны относиться к ним одинаково. Например,

 int a[0];      //error: zero-sized array not allowed in ISO C++
int b[int()];  //error: zero-sized array not allowed in ISO C++
int c[int{}];  //error: zero-sized array not allowed in ISO C++

Но, похоже, в некоторых угловых случаях они не взаимозаменяемы.

  • При инициализации указателя:

    int *p = 0;     //ok
    int *q = int(); //error - by clang only
    int *r = int{}; //error - by gcc and clang both
    

    Увидеть НКУ а также лязг Сообщения. Я подозреваю, что это ошибка в обоих компиляторах, так как я ожидаю, что они взаимозаменяемы в этом контексте, но я был бы рад оказаться ошибочным. 🙂

  • При переходе на шаблон класса:

    template<int N> struct X{};
    
    X<0>      x1; //ok
    X<int{}>  x2; //ok (same as X<0>)
    X<int()>  x3; //error
    

    Увидеть НКУ а также лязг Сообщения.

    Я нахожу синтаксис X<int()> довольно знакомый, как я видел (и, вероятно, использовал) подобный синтаксис ранее, такой как в std::function<int()>аргумент шаблона int() как ожидается, будет тип функции (вместо 0не принимая аргументов и возвращаясь int, Но я хочу знать раздел спецификации, который говорит в этом контексте int() должен рассматриваться как функция тип и не эквивалентно int{} который всегда 0,

5

Решение

Выражения int() а также int{} оба являются значениями константных выражений целочисленного типа, которые оцениваются как ноль, и поэтому взаимозаменяемы с литералом 0 в любом контексте, где требуется целочисленное постоянное выражение prvalue целочисленного типа, которое оценивается как ноль.

Оба выражения удовлетворяют требованиям для константного выражения, как указано в 5.19 Выражения констант [expr.const].

относительно X<int()>стандарт указывает, что int() не интерпретируется как выражение в этом контексте:

14.3 Аргументы шаблона [temp.arg]

В Шаблон-аргумент, двусмысленность между тип-идентификатор и выражение решено к тип-идентификатор, независимо от формы соответствующего Шаблон-параметр.

Что касается преобразования указателей:

4.10 Преобразование указателей [conv.ptr]

Константа нулевого указателя является целочисленным константным выражением (5.19), имеющим тип целочисленного типа, равным нулю.
или тип значения std::nullptr_t,

Исходя из вышеприведенного пункта, оба int() а также int{} являются константными выражениями нулевого указателя. Это указывает на (очень незначительную) ошибку компилятора, хотя существует открытый отчет о дефектах (903) что может привести к изменению этого абзаца:

Среди CWG был твердый консенсус в отношении того, что только литерал 0 следует считать константой нулевого указателя, а не произвольным константным выражением с нулевым значением, как указано в настоящее время.

Следующая формулировка касается значения выражения int():

8.5 Инициализаторы [dcl.init]

Инициализация с нуля объекта или ссылки типа T означает:

[пропущенные пункты, которые не применяются]

если T является скалярным типом (3.9), объекту присваивается значение 0 (ноль), принимаемое как интегральное постоянное выражение,
преобразован в T

[…]

Инициализировать значение объекта типа T означает:

— если T является (возможно, cv-квалифицированным) типом класса (раздел 9) с предоставленным пользователем конструктором (12.1), то
вызывается конструктор по умолчанию для T (и инициализация некорректна, если T не имеет доступного по умолчанию
конструктор);

[пропущенные пункты, которые не применяются]

в противном случае объект инициализируется нулями.

Объект, инициализатором которого является пустой набор скобок, то есть (), должен быть инициализирован значением.

И для стоимости int{}:

8.5.4 Инициализация списка [dcl.init.list]

Инициализация списка объекта или ссылки типа T определяется следующим образом:

— Если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект
значение инициализации.

[пропущенные пункты, которые не применяются]

В противном случае, если в списке инициализатора нет элементов, объект инициализируется значением.

Все цитаты из C ++ Рабочий черновик стандарта N3337.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]