Статическое определение шаблона и явные ошибки создания экземпляра в MSVC

Мне интересно, почему следующий код работает отлично в gcc

#include <iostream>
using namespace std;

template<typename T>
struct F { 
  static T const value;
};

template<> 
struct F<int> { // Specialization
    static int const value; 
}; 

template struct F<int>;

template<typename T>
T const F<T>::value = sizeof(T);

template<>
int const F<int>::value = 42;

int main() {

    struct F<int> ma;
    cout << ma.value;

    return 0;
}

http://ideone.com/wvrurz

пока на MSVC 2012 я не могу его скомпилировать:

#include <iostream>
using namespace std;

template<typename T>
struct F {
  static T const value;
};

template<> 
struct F<int> { // Specialization
    static int const value; 
};

//template struct F<int>; // error C2950: 'F<int>' : cannot explicitly instantiate an explicit specialization

template<typename T>
T const F<T>::value = sizeof(T);

//template<>
//int const F<int>::value = 42; // error C2998: 'const int F<int>::value' : cannot be a template definition

int main() {

    struct F<int> ma;
    cout << ma.value;

    return 0;
}

Из того, что я прочитал в n3242 §14.7 5

как явное инстанцирование, так и объявление явного специализация не должна появляться в программе, если явно экземпляр следует декларации явной специализации.

и я считаю, что это так. Я что-то пропустил?

Ответ 1

TOO LONG; НЕ ПРОЧИТАЛ

  • msvc 2012 корректно отклоняет строку с надписью // error C2998,

  • прежняя диагностика, однако, является ошибочной и должна приниматься; как в более новые версии компилятора.

Примечание. Отчет об ошибке, относящийся к C2950, ​​можно найти, здесь.


Относительно C2950

msvc 2012 неверно выдает диагностику для данной строки.

template<class T> struct A;

template<>
struct A<int> { };

template struct A<int>; // legal

int main () { }

В стандарте указано, что явное инстанцирование должно содержать идентификатор simple-template-id, который является именно тем, что A<int>, и с указанным; это юридический С++.

14.6.2p3 Явная копия [temp.explicit]

Если явное инстанцирование относится к классу или классу-члену, специфицированный спецификатор типа в объявлении должен содержать идентификатор simple-template-id.

14.2p1 Имена специализированных шаблонов [temp.names]

Специализация шаблона (14.7) может ссылаться на шаблон-id:

simple-template-id:
         template-name < template-argument-list_opt >


Изменение формулировки: С++ 03 vs С++ 11

14.7.2p5 имеет новую формулировку, начиная с С++ 11, которая была введена после следующего отчета о дефекте:

14.7.2p5 Явная копия [temp.explicit]

Для заданного набора аргументов шаблона, если явное создание шаблона появляется после объявления явной специализации для этого шаблона, явное создание экземпляра не имеет эффекта.

Примечание: Kudos to @dyp для привлечения внимания к ранее связанному DR.


Относительно C2998

Эта ошибка является точной; вы не имеете в виду что-то, что зависит от параметра шаблона, это означает, что вы не должны использовать template<> для данного определения.

Более новые версии gcc выдает диагностику по этому поводу, а clang правильно отклоняет такое определение.

template<class T> struct A;

template<>
struct A<int> { 
  static int const value;
};

template<> int const A<int>::value = 42; // ill-formed, `value` does not depend on
                                         //              any template parameter since it's
                                         //              explicitly a part of `A<int>`

int main () { }
gcc   => foo.cpp:8:22: warning: too many template headers for A<int>::value (should be 0)
clang => foo.cpp:8:1: error: extraneous 'template<>' in declaration of variable 'value'
msvc  => foo.cpp(8) : error C2998: 'const int A<int>::value' : cannot be a template definition

Вышеуказанная диагностика верна.


Данная строка является нарушением следующего раздела стандарта:

14.7.3p5 Явная специализация [temp.expl.spec]

Члены явно специализированного шаблона класса определяются так же, как и члены обычного класса, и не используют синтаксис template<>. То же самое верно при определении члена явно специализированного класса-члена.