2013-07-16 12 views
7

static_assertの有用性を理解しようとしています。デザインを強制する際に役立つかどうか、もしあれば、どうすればよいかを知りたいと思います。static_assertを使用してテンプレートタイプを適用する

テンプレートタイプのサイズに基づいて部分的に特殊化された別のテンプレートクラス内に独自の実装を隠す一般的なテンプレートクラスがあります。

template <class T, size_t S = sizeof(T)> 
struct Helper; 

template <class T> 
struct Helper<T, sizeof(long)> 
{ 
    static T bar(); 
}; 

// ... other specializations ... 

template <class T> 
class Foo 
{ 
public: 

    T bar() 
    { 
     return Helper<T>::bar(); 
    } 
}; 

Tのサイズはヘルパーの専門によってサポートされている場合はFooのみサポートされています。ここでは、このデザインの簡単な概要です。たとえば、Foo<long>Foo<unsigned long>の両方がサポートされています。ただし、ユーザーがFoo<bool>を作成しようとしたとします。通常、これはエラーの原因となります。ヘルパーboolの特殊化は定義されていません。これは意図した動作です。

このデザインでstatic_assertを使用して、このインターフェイスのユーザーにとってより有用なエラーを提供する方法はありますか?

さらに、サイズが正しいかもしれないのに、ユーザーが特定の種類の使用を制限したいと考えています。たとえば、Foo<float>は許可しないでください。今、私がこれを強制することを知っている唯一の方法は、ドキュメンテーションの大胆なコメントです。 :)

+0

より一般的に考えると、それはサポートされている整数型ですか? 'char'、' bool'、 'float'などはありませんか? – Rapptz

+0

テンプレートタイプの制約または「概念」をSOで検索します。これを行うための機能は、最終段階でC++ 11から削除されました。同様の結果を達成する自動化された方法はそれほどありません。 – luke

+0

@Rapptz、 'char'、' int'、 'long'は、' unsigned'バージョンと一緒にサポートされるべきです。 'sizeof(int)== sizeof(long)== sizeof(unsigned long)'の場合、 'int'、' long'、 'unsigned long'のコードは同じです。 – Zeenobit

答えて

1

私はここの回答やコメントを組み合わせることにより、この問題のより良い解決策を考え出しました。

私はそうのような静的型チェッカーを定義することができます。

template <class A, class B> 
struct CheckTypes 
{ 
    static const bool value = false; 
}; 

template <class A> 
struct CheckTypes<A, A> 
{ 
    static const bool value = true; 
}; 

わからない、そのような構造体は、すでに標準ライブラリに存在するかどうか。とにかく、その後はFooに、私が使用しての種類とサイズを確認することができます。

static_assert((sizeof(T) == sizeof(long) || sizeof(T) == sizeof(int)) && !CheckTypes<T, float>::value, "Error!"); 
+1

を追加する必要があります.std :: is_same –

+1

sizeofを使用すると安全ではありません。それはちょうどサイズです。 longとintは同じサイズで、intだけを保持するランダム構造も同じサイズになります。 –

13

それが唯一のテンプレートクラスの専門のために働くことができた場合は、静的アサートを上げるデフォルトのテンプレートクラスを持っていますがない場合

template <class T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(T) == -1,"You have to have a sepecialization for Helper!"); 
} 

デフォルトのテンプレートクラスのみが選択されますより良い専門化、そのためにアサーションが上昇するでしょう。

同じ手法を使用して型を禁止することはできますが、静的なアサート検査に使用される別のテンプレートパラメータが必要になります。

template <class T, class G = T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(G) == -1,"You have to have a sepecialization for Helper!"); 
} 

template <class G> 
struct Helper<float,G> 
{ 
    static_assert(sizeof(G) == -1,"You can't use float !"); 
} 

template <> 
struct Helper<int> 
{ 
//This is a good specialization 
}; 

その後、あなたはこれらの変数でそれを試すことができます。

Helper<bool> a; //"You have to have a sepecialization for Helper!" 
Helper<float> b; //"You can't use float !" 
Helper<int> c; //compiles OK 
+1

私は 'static_assert(false、...)'が欲しいと思っています。 'static_assert'は、最初の引数がfalseの場合にエラーを出力します。 –

+0

+1の実用的な答え – sehe

+9

これはそのままでは動作しません - ( 'static_assert(sizeof(T)== 0、...);'のような)アサーションを依存させる必要があります。インスタンス化ではなく宣言のポイント。 – Angew

3

http://en.cppreference.com/w/cpp/header/type_traits

std::is_base_ofstd::is_convertibleがあなたの最初の問題とし、第二のためとして役立つ可能性があり、

static_assert(!std::is_same<float,T>(),"type can't be float");

うまくいけば、これはOPがおそらく4年間の罪で答えを見つけたと仮定して、この質問につまずいた他の誰かを助けますそれは尋ねられました:

関連する問題