2016-11-20 2 views
7

Clang(3.8)とGNU C++(4.9)のテンプレートインスタンス化のルールは同じではないようです。ここでの例である:GNU C++とClangのテンプレートインスタンス化

#include <cstddef> 

template <bool> 
class Assert { 
    Assert();   // private constructor for Assert<false> 
}; 

template <> 
class Assert<true> { // implicit public constructor for Assert<true> 
}; 

template <size_t N> 
class A { 
}; 

template <class T, size_t N> 
T foo(A<N>) { 
    return T(N - 1); 
} 

template <class T> 
T foo(A<0>) {  // foo is not defined for N=0 
    Assert<false>(); 
    return T(0); 
} 

int main(int argc, char **argv) { 
    foo<int>(A<3>()); 
    return 0; 
} 

この最小限の例では、タイプTと自然数N上に一般化されるテンプレート機能、fooを示しています。この関数はN=0では定義されていませんので、このように使用すると、Assertクラスを使用してコンパイラエラーを通知したいと考えています。

このコードはGNUコンパイラ(およびVisual C++ 2015も同様です)でも受け入れられますが、Clangは「プライベートコンストラクタをクラスAssert<false>で呼び出す」というエラーを出します。

だから誰ですか?このテンプレートをインスタンス化する必要はありません。

編集:Clangの標準の解釈を受け入れることで、テンプレートのコンパイル時のチェックを強制的に行うことができますパラメーター?

答えて

5

Assert<false>は依存型ではないため、clangが正しいと思います。

http://en.cppreference.com/w/cpp/language/dependent_name

非依存の名前はテンプレート定義のポイントを見上げて、結合されています。このバインディングは、テンプレートのインスタンス化の時点でより良い一致がある場合でも保持されます。

有効ではない特殊化は行わないでください。一般的な目的にし、static_assert(依存値付き)を使用して、無効なテンプレート引数の型/値をチェックします。標準のクランの解釈を受け入れstatic_assert(std::is_same<T, int>::value)static_assert(N != 0)

+0

したがって、 'foo 'がインスタンス化されない場合でも 'Assert 'が検索され、チェックされますか?それは余分な仕事ではありませんか?とにかく、このように動作するとすれば、テンプレートパラメータに対するコンパイラのアサーションの標準的な方法は何ですか? (私はそれに応じて質問を編集しました) – vukung

+0

@vukung実際には、テンプレートがインスタンス化されるたびにではなく、テンプレートが定義されているときにコンパイラが 'Assert 'を一度検索しなければならないので、 – Oktalist

+0

決して使用されないコードを書くのはなぜですか?それはあなたのための余分な仕事のように聞こえる。 – xaxxon

5

、テンプレートパラメータのコンパイル時のチェックを強制する標準的な方法は何ですか?

あなたはA<0>ためfoo()の「専門」/過負荷をドロップすると、次のように一般的なテンプレートを定義することができます。

template <class T, size_t N> 
T foo(A<N>) { 
    Assert<N != 0>(); 
    return T(N - 1); 
} 

あなたがあなた自身の静的アサートを定義する必要はありませんC++ 11で提供言語を使用することができますstatic_assert

template <class T, size_t N> 
T foo(A<N>) { 
    static_assert(N!=0, "N must be positive"); 
    return T(N - 1); 
} 
5

両方のコンパイラが正しいです。いつものように、これは[temp.res]/8によって制御されます:タイプ名で名前

知ることは、すべてのテンプレート の構文をチェックすることができます。このプログラムは、必要な一切の診断、病気に形成されていない場合:

  • 有効な分業がテンプレートやconstexpr ifの文([STMTのサブステートメントのために生成することはできません。 テンプレートおよびテンプレート内)]場合は、インスタンス化、または可変長引数テンプレートの

  • すべての有効な特殊化は、空のテンプレートパラメータパックを必要とする、または

  • すぐにその定義を以下のテンプレートの仮想的なインスタンス化されていませんテンプレートパラメータに 依存しない構築物、または病気に起因形成される

  • 仮説インスタンスにおけるそのような構築物の解釈は任意ACに構築対応 の解釈は異なっていますテンプレートのインスタンス化。

あなたのテンプレートは、3番目の箇条書きの抵触実行します。正解のよう

、いずれかの適切なstatic_assertを使用することができ、または明示的に望ましくない過負荷を削除することができます。

template <class T> 
T foo(A<0>) = delete; 

前者はより良いエラーメッセージを可能にする、後者は他のメタプログラミングをよりうまく演じています。

関連する問題