25
template <int answer> struct Hitchhiker {
  static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

で一般的なテンプレートのインスタンス化を無効にしようとしているときに、テンプレートがインスタンス化されていない場合でも上記のコードがアサート エラーを生成することをstatic_assert発見しました。clanggccHitchhiker42

いじってみると、次のように主張していることがわかりました。

template <int answer> struct Hitchhiker {
  static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

両方のコンパイラで同じように動作します。アサートは、一般的なテンプレートがインスタンス化された場合にのみ開始されます。

標準は何と言っていますか、どのコンパイラが正しいですか?

g++ 4.9.2
clang++ 3.50
4

2 に答える 2

14

@TartainLlama が見つけた引用

定義の直後にあるテンプレートの仮想的なインスタンス化が、テンプレート パラメーターに依存しない構造のために形式が正しくない場合、プログラムは形式が正しくありません。診断は必要ありません。

N4296 [temp.res]/8

これは、プライマリ テンプレート ( が含まれているテンプレート) が定義された直後に適用されstatic_assertます。したがって、後の特殊化 ( for 42) はまだ存在しないため、考慮できません。

次の問題は、static_assert( sizeof(answer) != sizeof(answer), に依存するかどうかanswerです。意味的にはそうではなく、構文的にはそうであり、標準的には次のとおりです。

テンプレート内では、インスタンス化ごとに異なるセマンティクスを持つ構成要素があります。このような構成は、テンプレート パラメーターに依存します。

N4296 [temp.dep]/1

コンストラクトsizeof(answer) != sizeof(answer)は、インスタンス化ごとに違いはありません。したがって、そのような構成はテンプレート パラメーターに依存しません。つまり、全体static_assertはテンプレート パラメータに依存しません。

したがって、プログラムの形式が正しくないため、診断は必要ありません。任意の診断 (static_assert失敗など) を発行することは、有効なコンパイラの動作です。問題がないのは、有効なコンパイラの動作です。不正な形式で診断が不要なプログラムからコンパイルされたプログラムの動作は、標準では定義されていません。これは未定義の動作です。鼻の悪魔は許可されています。

派手な試み (現在の神のsizeof(int[answer])!=sizeof(int[answer])コンパイラを喜ばせるかもしれませんが、プログラムをより適切に形成することはできません。

コンパイラがあなたを捕まえる可能性が低いケースを作ることができますが、コンパイラがあなたを捕まえる能力に関係なく、不正な形式は残ります。原則として、C++ はそれ自体 (およびそのコンパイラ) に、無効なテンプレート コードを「インスタンス化よりも前に」見つける自由を残したいと考えています。これは、テンプレート コードがおそらく正当なコードを生成する必要があることを意味します。

みたいな=deleteメッセージを添えて欲しいかも。

于 2015-05-06T15:42:11.660 に答える