Подтвердить что ты не робот

Что {} в void ({})?

Рассмотрим следующий фрагмент:

auto f() { return void({}); }
int main() { f(); }

Что именно {} в void({})?
Как это интерпретируется?

Просто из любопытства, конечно. В любом случае, отпустите еще немного.

Обратите внимание, что оба GCC 6.1 и clang 3.8 скомпилируют его без ошибок (-std=c++14 -pedantic).
Последний не жалуется, первый показывает предупреждение:

warning: list-initializer для неклассического типа не должен быть заключен в скобки

Используя -pedantic-errors вместо этого, GCC заканчивается ошибкой, в то время как clang компилирует ее.

Является ли это несоответствие ошибкой одного из двух компиляторов?
Я имею в виду, это допустимый код, который должен быть принят или нет?

4b9b3361

Ответ 1

Конверсии с типом void, а также возможность возврата значения void с самого начала присутствуют на языке С++. Единственная проблема, которая вызывает вопросы, - это роль {} в этом контексте.

Быстрый эксперимент с clang

int a({});

генерирует сообщение об ошибке

error: cannot initialize a variable of type 'int' with an rvalue of type 'void'

который указывает, что clang интерпретирует {} как значение void. Это, по-видимому, нестандартное поведение. Я не вижу места в спецификации языка, который сказал бы, что {} должен давать значение void в этом контексте.

Но так как это происходит в clang, нет ничего необычного в компиляции void({}) в clang. Любое значение в С++ может быть преобразовано в тип void, что означает, что до тех пор, пока компилятор принимает {} в этом контексте, остальное просто следует естественным образом.

В GCC на самом деле это ошибка в режиме -pedantic-errors

error: list-initializer for non-class type must not be parenthesized

так формально это "ошибка", а не "предупреждение" в GCC.


Что на самом деле происходит здесь, так это то, что комбинация открытия ({ и закрытия }) заставляет эти компиляторы интерпретировать его как расширение языка GNU C, известное как Выражение выражений (кстати, также поддерживается clang). Это, например, то, что делает следующий код компиляции

int a = ({ 3; });

В этом расширении выражение ({}) рассматривается как выражение выражения типа void. Однако это конфликтует с синтаксисом равномерной инициализации в С++.