У меня есть следующий код:
template <typename TC>
class C
{
struct S
{
template <typename TS>
void fun() const
{}
};
void f(const S& s)
{
s.fun<int>();
}
};
// Dummy main function
int main()
{
return 0;
}
При сборке с gcc 9.2 и clang (9.0) я получаю ошибку компиляции из-за template
ключевого слова, необходимого для вызова fun
. Clang показывает:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
Я не понимаю, почему компилятор считает fun
зависимое имя в контексте f
, так как f
это не сам шаблон. Если я заменю C
обычный класс вместо шаблона, ошибка исчезнет; однако, я не понимаю, почему в первую очередь должна быть ошибка, поскольку она не зависит и S
не f
зависит TC
.
Как ни странно, MSVC 19.22 компилирует это просто отлично.
нота
Перед голосованием закройте как dupe of Где и почему я должен поставить ключевые слова "template" и "typename"? пожалуйста, подумайте, что это особый случай, когда даже если S
это действительно зависимое имя, в контексте f
оно не будет зависимым, если бы не тот факт, что они являются членами текущего экземпляра.
Ответы:
Рассмотрим :
s.a<0>(i)
анализируется как выражение, содержащее две операции сравнения<
и>
, и это нормально для # 1, но не для # 2.Если это изменено , чтобы
s.template a<0>(i)
затем # 2 ОК и # 1 не удается. Таким образом,template
ключевое слово здесь никогда не бывает лишним.MSVC способен интерпретировать выражение
s.a<0>(i)
в одной и той же программе в обоих направлениях. Но это не правильно в соответствии со Стандартом; каждое выражение должно иметь только один синтаксический анализ, с которым должен работать компилятор.источник
C
либо другую, но вы никогда не сможете создать оба экземпляра.template
Ключевое слово здесь еще ненужной ИМХО, потому которыйS
получает взял зависит от того ,C
инстанцировании. Безtemplate
ключевого слова вы сможете создать оба экземпляра, и поведение f будет отличаться для каждого экземпляра.<
может быть оператором сравнения в одном экземпляре шаблона и открывающей угловой скобкой в другом экземпляре. Это необходимо для того, чтобы компиляторы могли анализировать шаблоны в AST (с заполнителями для типов шаблонов).fun
может или не может быть функцией шаблона (или может не существовать вообще) в зависимости от параметра шаблонаclass C
.Это потому, что вы можете специализироваться
S
(без специализацииC
):Поскольку компилятор хочет знать,
fun
является ли шаблон шаблоном при первом просмотреclass C
(перед заменой параметра шаблона),template
это необходимо.источник
S
шагом является возможность доступа к этим новым определениямf
. Если они не могут, иметь это ограничение не имеет смысла, потомуf
что не сможет их увидеть в любом случае.f
таки нашли.