Зависимые имена шаблонов и C 20 ADL

#c #templates #language-lawyer #c 20 #argument-dependent-lookup

#c #шаблоны #язык-юрист #c 20 #зависящий от аргумента поиск

Вопрос:

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

 namespace N {
    template<class>
    struct C { };

    template<int, class T>
    void foo(C<T>);
}

template<class T>
void bar(N::C<T> c) {
    foo<0>(c);
}

int main() {
    N::C<void> c;
    bar(c);
}
 

И GCC, и Clang не могут скомпилировать этот код в соответствии со стандартом C 17 (с -Werror ), потому что (согласно моему пониманию) в C 17 ADL не работает, когда присутствуют явные аргументы шаблона <...> (если только имя уже не установлено в качестве имени шаблона), поэтому foo независимое имя, котороене найдено.

В C 20 правила ADL претерпевают изменения, и явные аргументы шаблона не препятствуют ADL. Теперь кажется, что foo это становится зависимым именем, которое должно разрешаться через ADL. Однако у GCC и Clang разные мнения о достоверности этого кода. CLang компилирует его без ошибок, но GCC (10.2, -std=c 2a ) жалуется:

error: 'foo' was not declared in this scope; did you mean 'N::foo'?

В режиме C 17 Clang выдает следующее предупреждение:

warning: use of function template name with no prior declaration in function call with explicit template arguments is a C 20 extension

ДЕМОНСТРАЦИЯ.

У меня есть три связанных вопроса:

  1. Какой компилятор правильный и почему?
  2. В C 17 foo считается ли foo<0>(c) in зависимым именем?
  3. В C 20 foo считается ли foo<0>(c) in зависимым именем?

Комментарии:

1. Fwiw: gcc trunc в режиме C 20 тоже компилирует его, поэтому, похоже, они добавили эту функцию после 10.2.

Ответ №1:

Это P0846, который является особенностью C 20. Похоже, что gcc еще не реализует это.

Это не вопрос зависимого имени или нет, это вопрос о том, знает ли компилятор, что foo ссылается на шаблон или нет, и поэтому foo< выполняет сравнение или начинает выполнять параметры шаблона.

В C 17 компилятор должен был уже знать, что это foo имя шаблона (которое вы могли бы выполнить, добавив using N::foo; ), чтобы выполнить ADL, в C 20 это уже не так — теперь правило таково, что если неквалифицированный поиск находит шаблон или ничего, мы также рассматриваем его какбыть шаблоном.


Зависимость foo не изменилась в результате этой статьи. In foo<0>(c); , foo по-прежнему является зависимым именем. Правило в [temp.dep] из C 17 было:

В выражении вида:

postfix-expression ( expression-listopt )

где постфиксное выражение является неквалифицированным идентификатором, неквалифицированный идентификатор обозначает зависимое имя, если

  • любое из выражений в списке выражений является расширением пакета,
  • любое из выражений или связанных списков инициализации в списке выражений зависит от типа, или
  • неквалифицированный идентификатор — это идентификатор шаблона, в котором любой из аргументов шаблона зависит от параметра шаблона.

Здесь применяется второй маркер — c зависит от типа. Формулировка C 20 такая же. Проблема здесь заключалась не в том, что foo это не зависело от C 17. Просто правило было, когда мы foo< , мы не знаем, что foo это шаблон, поэтому он считается оператором меньше, чем оператор, и тогда происходит сбой.

Комментарии:

1. Но является foo ли зависимое имя? Если все имена попадают в две категории, это должен быть правильный вопрос.

2. @Evg В C 17 это тоже зависит… если при поиске удалось найти шаблон, такой, что это выражение может быть правильно проанализировано. «Зависимость» имени не изменилась в результате этой статьи.