web-dev-qa-db-ja.com

テンプレート関数がどこからも呼び出されない場合でも、static_assertがコンパイルに失敗する

私はg ++ 4.6.3(ubuntu 12.04の現在のデフォルトパッケージ)にフラグc ++ 0xを付けて使用しています。

template <typename T>
inline T getValue(AnObject&)
{
    static_assert(false , "this function has to be implemented for desired type");
}

コンパイルエラーあり:

static_assertion failed "this function has to be implemented for the desired type"

この関数をまだどこにも呼び出さない場合でも

それはg ++のバグですか?この関数は、コードのどこかで呼び出された場合にのみインスタンス化されるべきではありません。

34

これは、条件がテンプレートパラメータにまったく依存しないためです。したがって、コンパイラはそのテンプレートをインスタンス化する前でも評価でき、評価でfalseが得られた場合、関連するコンパイルエラーメッセージが生成されます。

つまり、これはバグではありません。多くのことは、テンプレートがインスタンス化されて初めて確認できますが、コンパイラーが以前に実行できる他の有効性チェックもあります。これが、たとえばC++が2フェーズの名前ルックアップを備えている理由です。コンパイラーは、100%発生する可能性が高いエラーを見つけるのを手助けしようとしています。

27
Andy Prowl

標準は[temp.res]/8で述べています

有効な特殊化を生成できるテンプレート定義の診断は発行されません。テンプレート定義に対して有効な特殊化を生成できず、そのテンプレートがインスタンス化されていない場合、テンプレート定義は不正な形式であり、診断は必要ありません。 ... [注:テンプレートがインスタンス化されると、この標準の他のルールに従ってエラーが診断されます。これらのエラーが正確に診断されるのは、実装の品質の問題です。 —エンドノート)

コンパイルする関数テンプレートをインスタンス化する方法はありません。そのため、テンプレート定義の形式が正しくなく、インスタンス化されていなくても、コンパイラーはそれを拒否できます(ただし必須ではありません)。

あなたはそれをこのように機能させることができます:

template<typename T>
struct foobar : std::false_type
{ };

template <typename T>
inline T getValue(AnObject&)
{
    static_assert( foobar<T>::value , "this function has to be implemented for desired type");
}

これで、コンパイラは関数テンプレートをすぐに拒否できません。インスタンス化されるまで、value == trueを持つfoobarの特殊化があるかどうかわからないためです。インスタンス化されると、関連するfoobar<T>の特殊化がインスタンス化され、静的アサーションは必要に応じて失敗します。

55
Jonathan Wakely

これは実際にはコメントですが、コード例が必要です。

聖なる標準のstatic_assertの表現は、その効果をインスタンス化されたコードに限定しません。

ただし、コード

template <typename T>
inline T getValue(int&)
{
    typedef char blah[-1];  // Common C++03 static assert, no special semantics.
}

int main()
{}

また、質問を強調するMinGW g ++ 4.7.2でコンパイルできません。

I think答えは、g ++が正しいこと、およびこのためのコンパイルエラーを生成しないVisual C++ 11.0は間違っていることですが、関連する分析を提供するのは難しいでしょう聖なる基準の聖句の。

コンパイラの違いの実際的な結果は、現在、動作についてrelyを実行できないことです。