Шаблоны: функция шаблона плохо работает с функцией члена шаблона шаблона

Это минимальный тестовый пример некоторого кода, который у меня есть. Он терпит неудачу, когда пытается оценить a.getResult<B>():

test.cpp: In function 'void printStuff(const A&)':
test.cpp:6: error: expected primary-expression before '>' token
test.cpp:6: error: expected primary-expression before ')' token

Код:

#include <iostream>

template< class A, class B>
void printStuff( const A& a)
{
    size_t value = a.getResult<B>();
    std::cout << value << std::endl;
}

struct Firstclass {
    template< class X >
    size_t getResult() const {
        X someInstance;
        return sizeof(someInstance);
    }
};

int main(int, char**) {
    Firstclass foo;

    printStuff<Firstclass, short int>(foo);
    printStuff<Firstclass, double>(foo);

    std::cout << foo.getResult< double >() << std::endl;

    return 0;
}

Если я прокомментирую функцию printStuff и где она вызвала, вызов foo.getResult< double >() компилируется и делает то, что ожидается.

Любая идея, что происходит? Я некоторое время работаю с расширенным шаблоном кода и никогда не встречал ничего подобного.

Ответ 1

Когда вы ссылаетесь на шаблон, который является членом зависимого типа, вы должны добавить его с ключевым словом template. Вот как выглядит вызов getResult внутри printStuff

size_t value = a.template getResult<B>();

Это похоже на использование ключевого слова typename при обращении к вложенным именам типов в зависимом типе. По некоторым причинам бит о typename с вложенными типами довольно хорошо известен, но аналогичное требование для template с вложенными шаблонами относительно неизвестно.

Обратите внимание, что общая структура синтаксиса немного отличается. typename всегда помещается перед полным именем типа, а template вставлен в середину.

Опять же, это необходимо только при обращении к члену шаблона зависимого типа, который в приведенном выше примере будет A в printStuff. Когда вы вызываете foo.getResult<> в main, тип foo не зависит, поэтому нет необходимости включать ключевое слово template.

Ответ 2

Ваш код плохо сформирован в соответствии со стандартом С++ 14.2/4:

Когда имя спецификатора шаблона члена появляется после . или -> в постфиксном выражении или после вложенного имени-спецификатора в идентификаторе с квалификацией, а постфиксное выражение или идентификатор квалифицированного пользователя явно зависит по шаблону-параметру (14.6.2), имя шаблона члена должно иметь префикс с ключевым словом template. В противном случае предполагается, что имя называется не-шаблоном.

Итак, вы должны написать size_t value = a.template getResult<B>();