Mam następujący kod:
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;
}
Kiedy buduję to z gcc 9.2 i clang (9.0), pojawia się błąd kompilacji, ponieważ template
słowo kluczowe jest wymagane do wywołania fun
. Clang pokazuje:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
Nie rozumiem, dlaczego kompilator myśli fun
w kontekście o nazwie zależnej f
, ponieważ f
sam nie jest szablonem. Jeśli zmienię C
się na zwykłą klasę zamiast szablonu, błąd zniknie; Jednak nie widzę dlaczego nie powinno być błąd w pierwszej kolejności, ponieważ ani S
nie f
zależą TC
.
Co dziwne, MSVC 19.22 dobrze to kompiluje.
Uwaga
Przed głosowaniem, aby zamknąć jako duplikat Gdzie i dlaczego muszę umieścić słowa kluczowe „szablon” i „typename”? proszę wziąć pod uwagę, że jest to szczególny przypadek, w którym nawet jeśli S
jest to nazwa zależna, w kontekście f
nie byłaby zależna, gdyby nie fakt, że są członkami bieżącej instancji.
źródło
Odpowiedzi:
Zastanów się :
s.a<0>(i)
jest analizowany jako wyrażenie zawierające dwie operacje porównania<
i>
, i jest to w porządku dla # 1, ale kończy się niepowodzeniem dla # 2.Jeśli to zostanie zmienione na,
s.template a<0>(i)
to nr 2 jest w porządku, a nr 1 kończy się niepowodzeniem. Dlategotemplate
słowo kluczowe nigdy nie jest tutaj zbędne.MSVC jest w stanie interpretować wyrażenie na
s.a<0>(i)
dwa sposoby w tym samym programie. Ale to nie jest poprawne zgodnie ze Standardem; każde wyrażenie powinno mieć tylko jedną analizę, z którą kompilator sobie poradzi.źródło
C
lub innej, ale nigdy nie możesz utworzyć jednej i drugiej. Słowotemplate
kluczowe w tym miejscu jest nadal niepotrzebne IMHO, ponieważ to, któreS
zostanie wybrane, zależy od tego, któraC
instancja. Beztemplate
słowa kluczowego można utworzyć jedno i drugie, a zachowanie f byłoby inne dla każdego wystąpienia.<
nie jest operatorem porównania w jednej instancji szablonu i nawiasiem kątowym otwarcia w innej instancji. Ma to na celu zapewnienie, że kompilatory mogą przetwarzać szablony na AST (z symbolami zastępczymi dla typów szablonów).fun
może, ale nie musi, być funkcją szablonu (lub może w ogóle nie istnieć) w zależności od parametru szablonuclass C
.To dlatego, że możesz się specjalizować
S
(bez specjalizacjiC
):Ponieważ kompilator chce wiedzieć, czy
fun
jest szablonem, czy nie przy pierwszym spojrzeniuclass C
(przed podstawieniem parametru szablonu),template
jest wymagany.źródło
S
będą kiedykolwiek dostępnef
. Jeśli nie mogą, ograniczenie to nie ma sensu, ponieważ if
tak nie będzie w stanie ich zobaczyć.f
go znajdują.