В явном спецификаторе константное-выражение, если оно указано, должно быть контекстно преобразованным постоянным выражением типа bool ([выражение.конст]). Явный спецификатор
explicitбез константное-выражение эквивалентно явному-спецификаторуexplicit(true). Если константное выражение имеет значениеtrue, функция явная. В противном случае функция не является явной. А(токен, следующий заexplicit, анализируется как часть явный спецификатор.
Какова цель последнего предложения выше? Разве это не очевидно из первого определения грамматического термина «явный спецификатор», приведенного ниже?
явный спецификатор:
explicit ( constant-expression )
explicit





Действует следующее:
struct A {
(A)(/*...*/); //1
};
//1 объявляет конструктор A со списком параметров /*...*/. Это разрешено, поскольку грамматика деклараторов позволяет добавлять дополнительные круглые скобки в разных местах, например. вокруг идентификатора декларатора A.
Тогда возникает вопрос, как
struct A {
explicit (A)(/*...*/); //2
};
следует интерпретировать.
Раньше в C++20 //2 означало бы, что у нас есть та же сигнатура конструктора, что и в //1, но помеченная explicit, а грамматика C++20 без рассматриваемого предложения по-прежнему позволяла бы анализировать его таким образом, анализируя (A) как часть явный спецификатор не будет работать, поскольку () не является допустимым синтаксисом декларатора и A не является выражением.
Предложение, о котором вы спрашиваете, приводит к тому, что вторая интерпретация делает его неверным. В предложении не содержится конкретного аргумента относительно того, почему, но я полагаю, что оно предназначено для того, чтобы избежать ошибок, поскольку что-то вроде
struct A {
explicit(A) (/*...*/); //3
};
похоже, что explicit(A) был явным спецификатором, хотя, согласно самой грамматике, он не будет анализироваться таким образом.
Это также упоминается как критическое изменение в [diff.cpp17.class]/1.
Насколько я могу судить, это только делает ранее правильно сформированный код плохо сформированным. Я не думаю, что без этого предложения существует какая-либо двусмысленность. Единственный некорректный код — это объявления с дополнительными круглыми скобками вокруг идентификатора декларатора, которые, вероятно, никто не использует на практике.
который, вероятно, никто не использует на практике" обязательный xkcd.
Обратите внимание, что
struct foo { (foo)(){} };компилируется; иstruct foo { explicit (foo)(){} };не удается скомпилировать из-за вышеуказанного правила, делающего(частью «явного спецификатора». Без вышеуказанного правила это было бы неоднозначно.