Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template static definition and explicit specialization instantiation errors in MSVC

I'm wondering why the following code runs just fine in 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

while on MSVC 2012 I cannot get it to compile:

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

From what I read in n3242 §14.7 5

both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit instantiation follows a declaration of the explicit specialization.

and I believe this is the case. Am I missing something?

like image 797
Marco A. Avatar asked Jun 20 '14 18:06

Marco A.


1 Answers

TOO LONG; DIDN'T READ

  • msvc 2012 is correctly rejecting the line marked // error C2998,

  • the former diagnostic is however faulty and should be accepted; as it is in newer versions of the compiler.

Note: The bug report related to C2950 can be found, here.


Regarding C2950

msvc 2012 is wrong to issue a diagnostic for the line in question.

template<class T> struct A;

template<>
struct A<int> { };

template struct A<int>; // legal

int main () { }

The standard states that an explicit instantiation should contain a simple-template-id, which is exactly what A<int> is, and with that said; it is legal C++.

14.6.2p3 Explicit instantiation [temp.explicit]

If the explicit instantiation is for a class or member class, the elaborated-type-specifier in the declaration shall include a simple-template-id.

14.2p1 Names of template specializations [temp.names]

A template specialization (14.7) can be referred to by a template-id:

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


Change of wording: C++03 vs C++11

14.7.2p5 has some new wording starting from C++11, which was put in place after the following defect report:

  • 259. Restrictions on explicit specialization and instantiation

14.7.2p5 Explicit instantiation [temp.explicit]

For a given set of template arguments, if an explicit instantiation of a template appears after a declaration of an explicit specialization for that template, the explicit instantiation has no effect.

Note: Kudos to @dyp for bringing attention to the previously linked DR.


Regarding C2998

This error is accurate; you are not referring to something which depends on a template-parameter, this means that you should not use template<> on the definition in question.

Newer versions of gcc issues a diagnostic regarding it, and clang correctly rejects such a definition.

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

The above diagnostics are correct.


The line in question is a violation of the following section of the Standard:

14.7.3p5 Explicit specialization [temp.expl.spec]

Members of an explicitly specialized class template are defined in the same manner as members of normal class, and not using the template<>syntax. The same is true when defining a member of an explicitly specialized member class.

like image 147
Filip Roséen - refp Avatar answered Sep 22 '22 21:09

Filip Roséen - refp