Статическое определение шаблона и явные ошибки конкретизации специализации в 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;
}
в то время как на 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 ответ
СЛИШКОМ ДОЛГО; Не читал
msvc 2012 правильно отклоняет строку, помеченную
// error C2998
,первая диагностика, однако, ошибочна и должна быть принята; как это в новых версиях компилятора.
Примечание. Отчет об ошибках, связанных с C2950, можно найти здесь.
Относительно C2950
msvc 2012 неправильно выдавать диагностику для рассматриваемой линии.
template<class T> struct A;
template<>
struct A<int> { };
template struct A<int>; // legal
int main () { }
Стандарт гласит, что явная реализация должна содержать простой-template-id, который именно A<int>
есть, и с этим сказал; это законно C++.
14.6.2p3
Явная реализация[temp.explicit]
Если явное создание экземпляра относится к классу или классу-члену, уточненный спецификатор типа в объявлении должен включать простой-идентификатор шаблона.
14.2p1
Названия шаблонных специализаций[temp.names]
На специализацию шаблона (14.7) может ссылаться идентификатор шаблона:
simple-template-id: template-name < template-argument-list_opt >
Изменение формулировки: C++ 03 против C++ 11
14.7.2p5 имеет новую формулировку, начиная с C++ 11, которая была введена в действие после следующего отчета о дефектах:
14.7.2p5
Явная реализация[temp.explicit]
Для заданного набора аргументов шаблона, если явное создание шаблона появляется после объявления явной специализации для этого шаблона, явное создание экземпляра не имеет никакого эффекта.
Примечание: dyp @ 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<>
синтаксис. То же самое верно при определении члена явно специализированного класса члена.