#c #gcc #language-lawyer #c 20
#c #gcc #язык-юрист #c 20
Вопрос:
У меня создалось впечатление, что следующий код должен стать допустимым в соответствии с новым стандартом C 20:
struct Foo
{
int a, b;
};
template<Foo>
struct Bar
{};
Bar<{.a=1, .b=2}> bar;
Тем не менее, gcc 10.2.0
, с -std=c 20
set жалуется: could not convert ‘{1, 2}’ from ‘<brace-enclosed initializer list>’ to ‘Foo’
и Clang также не может скомпилировать этот фрагмент. Может кто-нибудь указать, почему он неправильно сформирован?
Комментарии:
1. Этот пример программы принят GCC 11 и MSVC 19.28, демонстрация: gcc.godbolt.org/z/Tfn4bcaaY
Ответ №1:
Этот шаблон-аргумент
{.a=1, .b=2}
не допускается в соответствии с грамматикой для шаблона-аргумента, который допускает только следующие конструкции:
шаблон-аргумент:
константное выражение
тип-идентификатор
id-выражение
Список инициализации в виде фигурных скобок не является ни одной из вышеперечисленных конструкций, на самом деле это инициализатор, поэтому его нельзя использовать в качестве аргумента шаблона.
Вы можете указать явно тип объекта, который вы используете в качестве аргумента шаблона:
Bar<Foo{.a=1, .b=2}> bar;
и это будет работать, поскольку это постоянное выражение.
Комментарии:
1. Это компилируется, но я не понимаю, почему компилятор не может сделать вывод здесь, и его вполне устраивает,
bar({.a=1, .b=2})
когдаbar
функция принимает аргумент типаFoo
. Можете ли вы объяснить, почему вычет здесь невозможен?2. Посмотрите
autoamp;amp; ref = {.a = 1, .b = 2};
, компилируется ли. Вычет типа аргумента шаблона иautoamp;amp;
вычет типа следуют тем же правилам. Я полагаю, что он также не будет компилироваться, и вам будет легче понять, почему это так..3. @TanveerBadar я не убежден. В случае OP нечего выводить, неизвестных типов нет.
4. Похоже, что это просто грамматика c , которая запрещает это: eel.is/c draft/temp.names#nt:template-argument-list это то, что является аргументом шаблона, а a
braced-init-list
— это инициализатор , а не постоянное выражение.5. Это CWG2450; ожидайте, что это будет исправлено, предположительно, даже с
-std=c 20
, через несколько месяцев (плюс или минус время реализации).
Ответ №2:
Это связано с грамматикой C . Вещи, используемые для аргументов шаблона, должны быть либо идентификаторами типов, либо именами идентификаторов, либо постоянными выражениями.
И связанный список инициализации не является выражением какого-либо вида. Они могут грамматически присутствовать только в небольшом количестве мест, в частности в тех, которые используются для инициализации объекта или переменной.
В прошлом это было не очень актуально, поскольку не было особых причин использовать связанный список инициализации для инициализации нескольких допустимых NTTP. Очевидно, что это изменилось, так что это своего рода недосмотр. Но это то, что говорится в стандарте C 20.