#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
У меня есть три связанных вопроса:
- Какой компилятор правильный и почему?
- В C 17
foo
считается лиfoo<0>(c)
in зависимым именем? - В 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 это тоже зависит… если при поиске удалось найти шаблон, такой, что это выражение может быть правильно проанализировано. «Зависимость» имени не изменилась в результате этой статьи.