10

次のコードが 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 で読んだことから

明示的なインスタンス化と明示的な特殊化の宣言の両方が、明示的なインスタンス化が明示的な特殊化の宣言に続く場合を除き、プログラムに現れてはなりません。

そして私はこれが事実だと信じています。何か不足していますか?

4

1 に答える 1

9

長すぎる; 読まなかった

  • 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>その通りです。それは正当な C++です。

14.6.2p3 明示的なインスタンス化 [temp.explicit]

明示的なインスタンス化がクラスまたはメンバー クラスに対するものである場合、宣言内の詳しい型指定子にはsimple-template-idが含まれます。

14.2p1 テンプレートの特殊化の名前 [temp.names]

テンプレートの特殊化 (14.7) は、 template-idによって参照できます。

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


表現の変更: C++03C++11

14.7.2p5には、 C++11から始まるいくつかの新しい文言があります。これは、次の欠陥レポートの後に配置されました。

14.7.2p5 明示的なインスタンス化 [temp.explicit]

テンプレート引数の特定のセットについて、そのテンプレートの明示的な特殊化の宣言の後にテンプレートの明示的なインスタンス化が表示された場合、明示的なインスタンス化は効果がありません。

:以前にリンクされたDRに注意を向けさせてくれた @dyp感謝します。


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<>明示的に特殊化されたクラス テンプレートのメンバーは、構文を使用せずに、通常のクラスのメンバーと同じ方法で定義されます。明示的に特殊化されたメンバー クラスのメンバーを定義する場合も同様です。

于 2014-06-20T20:30:15.240 に答える