2009-10-30 6 views
72

static_assert(...) 'C++0x'が問題を優雅に解決する例を教えてください。static_assertは何を行いますか?それは何のために使用しますか?

私は実行時に慣れていますassert(...)。いつ普通のassert(...)よりもstatic_assert(...)を好むべきですか?

また、boostには、BOOST_STATIC_ASSERTと呼ばれるものがあります。これはstatic_assert(...)と同じですか?

+0

さらに詳しいオプションについては、BOOST_MPL_ASSERT、BOOST_MPL_ASSERT_NOT、BOOST_MPL_ASSERT_MSG、BOOST_MPL_ASSERT_RELATION [http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual/asserts.html]を参照してください。 _MSGは、使い方を見つけたら特に便利です。 – KitsuneYMG

答えて

50

... SomeLibrary::Versionはむしろ#define D(1がC++ライブラリに期待するもの)であることよりも、静的定数として宣言されると仮定すると

#include "SomeLibrary.h" 

static_assert(SomeLibrary::Version > 2, 
     "Old versions of SomeLibrary are missing the foo functionality. Cannot proceed!"); 

class UsingSomeLibrary { 
    // ... 
}; 

実際SomeLibraryし、コードをコンパイルすることでコントラストは、すべてをリンクし、あなたがSomeLibraryの互換性のないバージョンをコンパイルする30分を費やしたことを見つけるためにのみその後、を実行可能ファイルを実行します。

@Arak、あなたのコメントに反応して:はい、あなたが持つことができますstatic_assertそれを見てから、どこ、ただ座っ:

class Foo 
{ 
    public: 
     static const int bar = 3; 
}; 

static_assert(Foo::bar > 4, "Foo::bar is too small :("); 

int main() 
{ 
    return Foo::bar; 
} 
 
$ g++ --std=c++0x a.cpp 
a.cpp:7: error: static assertion failed: "Foo::bar is too small :(" 
+1

私は少し混乱しています、 'static_assert'を非実行コンテキストに入れることができますか?非常に良い例です:) – AraK

+2

静的なアサートは、述語が真である場合にのみ定義されるオブジェクトの作成として通常実装されています。これは単にグローバル化するだろう。 – GManNickG

+0

元の質問に完全に答えているとは確信していませんが、素敵なデモ –

3

static_assertを1つ使用すると、構造(ネットワークやファイルなどの外部世界とのインターフェイス)が期待どおりのサイズになるようにすることができます。これは、誰かがその結果を実現することなく構造からメンバーを追加または変更する場合を捉えます。 static_assertはそれを受け取り、ユーザーに警告します。私の頭の上オフ

10

私はコンパイラの動作についての私の仮定を確保するためにそれを使用します、ヘッダー、libs、そして自分のコードさえ正しいです。例えばここでは、構造体が予想されたサイズに正しくパックされていることを確認します。クラスのラップで

struct LogicalBlockAddress 
{ 
#pragma pack(push, 1) 
    Uint32 logicalBlockNumber; 
    Uint16 partitionReferenceNumber; 
#pragma pack(pop) 
}; 
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6); 

stdio.hさんfseek()、私はenum Originで、いくつかのショートカットを取り、それらのショートカットがstatic_assertassertを超えるときは、選ぶべきstdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin) 
{ 
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET); 

によって定義された定数に合わせていることを確認しています動作はコンパイル時に定義され、実行時では定義されていません。これがではなく、である例では、パラメーターと戻りコードの検査が含まれます。

BOOST_STATIC_ASSERTは、条件が満たされない場合に不正なコードを生成するプレC++ 0xマクロです。その意図は同じですが、static_assertが標準化されており、より良いコンパイラ診断を提供する可能性があります。

96

スタティックアサートは、コンパイル時にアサーションを行うために使用されます。静的アサーションが失敗すると、プログラムは単純にコンパイルされません。これは、正確に32ビットのunsigned intオブジェクトに非常に依存するコードによっていくつかの機能を実装する場合など、さまざまな状況で便利です。このような静的なアサーションを置くことができます

static_assert(sizeof(unsigned int) * CHAR_BIT == 32); 

別のプラットフォームでは、異なるサイズのunsigned intタイプではコンパイルが失敗するため、開発者はコードの問題の部分に注意を向け、コードを再実装または再検査するようにアドバイスします。

別たとえば、あなたがvoid *関数へのポインタ(ハックが、時には便利です)など、いくつかの整数値を渡すこともできますし、あなたは積分値がポインタ

に適合することを確認するには、
int i; 

static_assert(sizeof(void *) >= sizeof i); 
foo((void *) i); 

あなたはcharタイプが負の値で

static_assert(CHAR_MIN < 0); 

またはその整数分周を締結している資産にしたいかもしれませんが、ゼロ

に向けて丸め
static_assert(-5/2 == -2); 

など。

多くの場合、静的アサーションの代わりにランタイムアサーションを使用できますが、実行時アサーションは実行時にのみ、また制御がアサーションを通過するときにのみ機能します。このため、ランタイムアサートが失敗すると、長期間にわたって検出されずに休止状態になる可能性があります。

もちろん、静的アサーションの式はコンパイル時定数でなければなりません。ランタイム値にすることはできません。実行時の値には他の選択肢はありませんが、通常のassertを使用します。

+0

これはいい答えです。私はあなたが私の+1を持っていることを知って欲しいと思います:) – AraK

+1

static_assertは2番目のパラメータとして文字列リテラルを必須としていませんか? –

+0

@ Trevor Hickey:はい、そうです。しかし、私はC++ 11の 'static_assert'を具体的に参照しようとしていませんでした。上の私の 'static_assert'は静的アサーションの抽象実装です。 (私は個人的にCコードのようなものを使用します)。私の答えは、静的アサーションの一般的な目的と、ランタイムアサーションとの違いについてのものです。 – AnT

9

BOOST_STATIC_ASSERTは、static_assert機能のクロスプラットフォームラッパーです。

現在、クラスに「概念」を適用するためにstatic_assertを使用しています。

例:上記のいずれかの条件が満たされていない場合

template <typename T, typename U> 
struct Type 
{ 
    BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value); 
    BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer); 
    /* ... more code ... */ 
}; 

これは、コンパイル時にエラーが発生します。

+3

C++ 11がリリースされた(そしてしばらく外出した)ので、static_assertはすべてのメジャーコンパイラのより新しいバージョンでサポートされるべきです。 C++ 14(テンプレートの制約が含まれていることを期待しています)を待つことができない人にとって、これはstatic_assertの非常に便利なアプリケーションです。 – Collin

2

これは元の質問に直接答えるものではありませんが、C++ 11より前にこれらのコンパイル時間チェックを実施する方法について興味深い研究をしています。

第2章(第2.1節)アンドレイAlexanderscuによってModern C++ Designのこの

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

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

マクロSTATIC_CHECK比較このようなコンパイル時のアサーションの思想()とstatic_assert()

STATIC_CHECK(0, COMPILATION_FAILED); 
static_assert(0, "compilation failed"); 
2

Inを実装しますコンセプトの欠如static_assertは、テンプレートなどの簡単で読みやすいコンパイル時の型チェックに使用できます。

template <class T> 
void MyFunc(T value) 
{ 
static_assert(std::is_base_of<MyBase, T>::value, 
       "T must be derived from MyBase"); 

// ... 
} 
関連する問題