Ошибка компилятора g++ или код неисправности?: "определение шаблона без шаблона"

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

Я упростил соответствующий код, чтобы создать пример с голубыми костями, о котором я говорю:

#include <iostream>
#include <string>
#include <type_traits>

template <class T, class Enable = void>
struct Foo;

template <class T>
struct Foo<T,
    typename std::enable_if<std::is_integral<T>::value>::type
>
{
    static std::string message;
};

template <class T>
struct Foo<T,
    typename std::enable_if<std::is_floating_point<T>::value>::type
>
{
    static std::string message;
};

template <class T, class Enable>
std::string Foo<T, Enable>::message;

В GCC 4.6 это дает ошибку компилятора: template definition of non-template ‘std::string Foo<T, Enable>::message. Проблема возникает из-за последних двух строк, где я просто определяю статическую переменную std::string Foo<T, Enable>::message.

Я смущен, почему это происходит. Ошибка компилятора исчезает, если я опускаю последние две строки (но, конечно, это вызывает ошибки компоновщика.) Является ли это ошибкой компилятора с GCC?

Ответ 1

Это работает только тогда, когда параметры вашего шаблона соответствуют частичной специализации:

template <class T>
std::string Foo<T,
    typename std::enable_if<std::is_integral<T>::value>::type
>::message;

template <class T>
std::string Foo<T,
    typename std::enable_if<std::is_floating_point<T>::value>::type
>::message;

Это указано в разделе 14.5.4.3 стандарта С++ 03. Идея состоит в том, что частичная специализация - это новый шаблон, а параметры шаблона членов, которые определены извне, должны соответствовать параметрам шаблона определения класса, чтобы он знал, к какому шаблону принадлежит член.

В вашем примере правило избегает определения члена сообщения для типов, которые не являются целыми или плавающими.