2012-01-21 13 views
5

私たちは、特定のポリシーまたはタイプでは動作しないいくつかのメソッドを持つ複雑なテンプレートクラスを持っています。したがって、これらの型を(コンパイル時に、型型を使用して)検出すると、私たちは素敵なメッセージで静的なアサーションを起動します。いくつかのメソッドを手動テンプレートのインスタンス化から除外できますか?

ここでは、多くの手動テンプレートインスタンシエーションも行っています。部分的には、メソッドをコンパイルしてメソッドをシンタックスチェックするように強制されます。また、ライブラリユーザーのコンパイル時間も短縮されます。問題は、静的アサーションが常に発生し、その結果、問題のテンプレートクラスを手動でインスタンス化できないということです。

回避策はありますか?

EDIT:EDIT2

// header 
template <typename T> 
class someClass 
{ 
    void someFunc() {} 
    void someFunc1() { static_assert(false, assertion_failed); } 
}; 

// source 
template someClass<int>; // Explicit instantiation 

は、ここでの例では、someFunc1()に失敗します。この場合、(明示的にインスタンス化され、それをより明確にするために、ここでは別の例である。この時間をあなたコメントを外して[2]とすると、静的アサーションが発生するはずです。コメントアウト[2]コメントを外して[1]をコメントアウトしてください。静的アサーションwi明示的にテンプレートをインスタンス化しているため、起動します。私はそれに伴うメリットのために明示的なインスタンシエーションを削除しないようにしたいと考えています(上記のメリットを参照)。

namespace Loki 
{ 
    template<int> struct CompileTimeError; 
    template<> struct CompileTimeError<true> {}; 
} 

#define LOKI_STATIC_CHECK(expr, msg) \ 
    { Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

template <typename T> 
class foo 
{ 
public: 

    void func() {} 
    void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); } 
}; 

template foo<int>; 
//template foo<double>; // [1] 

int main() 
{ 
    foo<int> a; 
    a.func1(); 

    foo<double> b; 
    //b.func1(); //[2] 

    return 0; 
} 
+0

問題の内容は明らかではありませんが、問題の範囲から見るとenable_ifはあなたのためです(http://www.boost.org/doc/libs/1_48_0/libs/utility/ enable_if.html) – bobah

+0

@bobah:それはまったく悪い考えではありません...私はそれを調べます。私が確認できる簡単な例を用意することができれば、答えとしてマークします。 – Samaursa

+1

私は細部の不足について不平を言う他の人に同意します。しかし、とにかく、これは私に鐘を鳴らしました: "問題は、静的なアサーションは常に解雇されるということです"。 http://www.boost.org/doc/libs/1_48_0/doc/html/boost_staticassert.html#boost_staticassert.templates、最後の発言:これはあなたの問題ですか? –

答えて

0

とそれは解決策が選択されたいくつかの下でコンパイルした場合に失敗します。コードの上にダミーテンプレートを置くことです

(私は良いないフルを言って、最後に説明します)良い程度の私の元の要件を満たしますタイプとは他の人の下で罰金。だから、:私のテンプレートコード、機能のこれらの種類(静的アサートや仕事、いくつかの種類に及び型特性を使用して、他人に失敗する可能性がありますしている、すなわちものの全てにおいて

struct dummyStruct {}; 

#define DUMMY_TEMP typename dummy 
#define DUMMY_PARAM dummyStruct 

namespace Loki 
{ 
    template<int> struct CompileTimeError; 
    template<> struct CompileTimeError<true> {}; 
} 

#define LOKI_STATIC_CHECK(expr, msg) \ 
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

template <typename T> 
class foo 
{ 
public: 

    void func() {} 
    template <typename T_Dummy> 
    void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); } 
}; 

template foo<int>; 
template foo<double>; // [1] 

int main() 
{ 
    foo<int> a; 
    a.func1<DUMMY_PARAM>(); 

    foo<double> b; 
    //b.func1<DUMMY_PARAM>(); //[2] - this is a static error 

    return 0; 
} 

[選択があり、その場合には異なるタイプのいくつかの異なる機能の])はクライアントから隠されています。だから私の実装では、余分なdummy parameterを追加することはOKの妥協です。

この機能は、特定のタイプのみで使用するように設計されています。さらに、私の本来の明示的なインスタンス化の問題は、この単純な技術によって解決されます。

2

さてさて、あなたは明示的なインスタンスを使用して、すべてのメソッドのインスタンス化を強制している場合、あなたがそのようなenable_ifなど問題のあるメソッドのインスタンス化を防ぐために、任意のコンパイル時のトリックで逃げることができないようにします。ランタイムにエラーを移動するのは簡単ですが、それは望ましくありません。

あなたができることは、リンクされた時間にエラーを移動することです。プログラムが潜在的に禁止された機能を呼び出す可能性のあるコードパスを含まないことを静的に保証しますが、エラーメッセージはあまり役に立ちませんあなたが課している制限について知らない人に。とにかく、解決策は、それらを定義禁止メンバ関数の特殊化を宣言したがないことです。

template<typename T> 
struct Foo { 
    void bar() { 
     std::cout << "bar\n"; 
    } 
    void baz() { 
     std:: cout << "baz\n"; 
    } 
}; 

template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail 

template struct Foo<int>; 
template struct Foo<char>; 

int main() { 
    Foo<int> f; 
    f.bar(); 
    // f.baz(); // uncommenting this line results in an ugly link time error 
    Foo<char> b; 
    b.bar(); 
    b.baz(); // works with Foo<char> 
} 

静的もはや間違いがクライアントコードで行われたときの素敵なエラーメッセージを与えるのを助けるませんが、あなたがしたい場合がありますアサート専門性を忘れると発砲するので、それらを残してください。

+1

インスタンスを作成している場合はそれが問題ありません。ここでは、問題を引き起こす明示的なインスタンス化を使用しています(上記の編集を参照) – Samaursa

+0

今後のSOerの混乱を避けるため、上記のコメントは編集の前に返されたものです) – Samaursa

+0

+1 **これは答えが必要です** **冗長な作業が必要ですが、配信します:) – CodeAngry

1

enable_ifは、正確なテンプレートメソッドのターゲティングのための柔軟なメカニズムです。あなたが後になっている可能性があります。例:

#include <string> 
#include <iostream> 

#include <boost/utility.hpp> 
#include <boost/type_traits.hpp> 
#include <boost/static_assert.hpp> 

template <class T> class mywrapper 
{ 
    T _value; 

    template <class V> 
    typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value) 
    { 
    BOOST_STATIC_ASSERT(boost::is_scalar<V>::value); 
    std::cout << "scalar: " << value << std::endl; 
    } 

    template <class V> 
    typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value) 
    { 
    BOOST_STATIC_ASSERT(boost::is_compound<V>::value); 
    std::cout << "compound: " << value << std::endl; 
    } 

public: 
    mywrapper(T const& value):_value(value) { } 
    void printval() { printval_(_value); } 
}; 

template class mywrapper<int>; 
template class mywrapper<std::string>; 

int main() 
{ 
    mywrapper<int> ival(333); 
    mywrapper<std::string> sval("test"); 

    ival.printval(); 
    sval.printval(); 
    return 0; 
} 
+0

私は現在 'boost'を持っていませんが、明示的なインスタンス化でもうまく動作しますか?たとえば、 'mywrapper template ;を入れた場合、' int main() 'の直前です。テンプレートmywrapper ;とそれぞれの関数では、それぞれスカラー型と複合型で作業していることを確認する静的なアサーションがあります。それはコンパイルされますか? – Samaursa

+0

は、静的なアサートとインスタンス化の例を更新しました – bobah

+0

ありがとうbobah!私は 'ブースト'が得られるとすぐにテストします。 – Samaursa

3

あなたは両方を持つことはできません:あなたは、明示的にタイプのインスタンスをインスタンス化を防止するための静的な主張を持つことはできません!これは明らかな矛盾です。ただし、ある種のメンバ関数がサポートされていない場合、この関数を条件付きで持つ基本クラスに移動することができます。この方法では、静的アサーションは使用せず、メンバー関数を削除するだけです。興味深い他の問題を紹介していることが分かります。メンバ変数の場所に関しては、私はあなたが得ることができる最高のものであると文脈で考えていると思います。ここで

がこのようになります方法の簡単な例です。bobahによって提案されたが、私はブーストを必要としない解決策を考え出すなかったので、私はenable_ifテストする機会を得られなかった

template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base; 
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ }; 
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } }; 

template <typename T> 
struct Foo: foo_base<T> { /* .... */ }; 

template struct Foo<int>; // will have foo() 
template struct Foo<double>; // will not have foo() 
関連する問題