C ++ - Почему здесь требуется ключевое слово 'template'? - PullRequest
9 голосов
/ 04 февраля 2020

У меня есть следующий код:

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;
}

При построении этого с g cc 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.

Как ни странно, MSV C 19.22 компилирует это просто отлично .


note

Перед голосованием закройте как дубликаты Где и почему я должен поставить ключевые слова "template" и "typename"? пожалуйста, примите во внимание это особый случай, когда даже если S действительно является зависимым именем, в контексте f оно не будет зависимым, если бы не тот факт, что они являются членами текущего экземпляра.

Ответы [ 2 ]

10 голосов
/ 04 февраля 2020

Рассмотрим :

template<typename T>
struct C
{
    struct S
    {
        int a = 99;
    };

    void f(S s, int i)
    {
        s.a<0>(i);
    }
};

template<>
struct C<long>::S
{
    template<int>
    void a(int)
    {}
};

int main()
{
    C<int>{}.f({}, 0); // #1
    C<long>{}.f({}, 0); // #2
}

s.a<0>(i) анализируется как выражение, содержащее две операции сравнения < и >, и это нормально для # 1, но не удается для # 2.

Если это изменено на s.template a<0>(i), тогда # 2 в порядке и # 1 завершается ошибкой. Таким образом, ключевое слово template здесь никогда не бывает избыточным.

MSV C способно интерпретировать выражение s.a<0>(i) в обоих направлениях в рамках одной и той же программы. Но это не правильно в соответствии со Стандартом; каждое выражение должно иметь только один синтаксический анализ, с которым должен работать компилятор.

7 голосов
/ 04 февраля 2020

fun может быть или не быть функцией шаблона (или может не существовать вообще) в зависимости от параметра шаблона class C.

Это потому, что вы можете специализироваться S (без специализации C):

template <> struct C<int>::S {};

Поскольку компилятор хочет знать, является ли шаблон fun шаблоном или нет, при первом взгляде на class C (до замены параметра шаблона) требуется template.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...