static_assertは何をするもので、何に使用しますか?


117

static_assert(...)( 'C ++ 11')が手元の問題をエレガントに解決する例を挙げていただけますか?

ランタイムに精通していassert(...)ます。いつ私static_assert(...)は通常よりも好むべきassert(...)ですか?

また、boostというものがありますがBOOST_STATIC_ASSERT、それは同じstatic_assert(...)ですか?


関連項目:その他のオプションについては、BOOST_MPL_ASSERT、BOOST_MPL_ASSERT_NOT、BOOST_MPL_ASSERT_MSG、BOOST_MPL_ASSERT_RELATION [ boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual/asserts.html]をご覧ください。_MSGは、それを使用する方法を理解すると特に便利です。
KitsuneYMG 2009年

回答:


82

頭の上から...

#include "SomeLibrary.h"

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

class UsingSomeLibrary {
   // ...
};

(C ++ライブラリで期待されるようSomeLibrary::Versionに)#defined ではなく、静的constとして宣言されていると仮定します。

実際にコンパイルすることとは対照的SomeLibraryとあなたのコード、リンクはすべて、唯一の実行可能ファイルを実行し、その後あなたは互換性のないバージョンをコンパイルする30分を費やしたことを見つけるためにSomeLibrary

@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:エラー:静的アサーションが失敗しました: "Foo :: barが小さすぎます:("

1
私は少し混乱していますstatic_assertが、非実行コンテキストに入れることはできますか?それはとても良い例のようです:)
AraK

3
はい、静的アサートは通常、述語がtrueの場合にのみ定義されるオブジェクトを作成するように実装されます。これは単にグローバルになるでしょう。
GManNickG 09/10/30

これが完全に元の質問に答える資格があるかどうかはわかりませんが、素晴らしいデモ
Matt Joiner '30

2
この回答では、<cassert>からのアサートstatic_assert
bitek

11
@monocoder:「...と対比」で始まる段落を参照してください。つまり、assertは実行時に状態をチェックし、static_assertはコンパイル時に状態をチェックします。したがって、アサートする条件がコンパイル時にわかっている場合は、を使用してくださいstatic_assert。プログラムが実行されるまで状態がわからない場合は、を使用しますassert
Mike DeSimone 2013年

131

静的アサートは、コンパイル時にアサーションを作成するために使用されます。静的アサーションが失敗すると、プログラムはコンパイルされません。これは、たとえば、unsigned int正確に32ビットのオブジェクトに厳密に依存するコードによっていくつかの機能を実装する場合など、さまざまな状況で役立ちます。あなたはこのように静的なアサートを置くことができます

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ます。


3
static_assertは、2番目のパラメーターとして文字列リテラルを持つ必要はありませんか?
Trevor Hickey

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

最初の例では、型の変数にパディングビットがないと想定していますunsigned int。これは規格によって保証されていません。タイプの変数は、unsigned int32ビットのメモリを合法的に占有し、そのうちの16ビットを未使用のままにすることができます(したがって、マクロUINT_MAXはに等しくなります65535)。道だから、最初の静的アサーション(「記述unsigned intオブジェクトが持つ誤解され、正確に32ビットを」)。説明と一致させるには、このアサーションも含める必要がありますstatic_assert(UINT_MAX >= 0xFFFFFFFFu)
RalphS

@TrevorHickeyはもうありません(C ++ 17)
luizfls

13

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

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

クラスの折り返しでstdio.hfseek()、私はいくつかのショートカットを取ってきたenum Originこれらのショートカットは、で定義された定数と合っていることをチェックstdio.h

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

上記の例のように、実行時ではなくコンパイル時に動作を定義static_assertするassert場合は、優先する必要があります。これが当てはまらない例には、パラメーターと戻りコードの検査が含まれます。

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


9

BOOST_STATIC_ASSERTstatic_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

7

の用途の1つはstatic_assert、構造(つまり、ネットワークやファイルなどの外界とのインターフェース)が、期待したサイズと正確に一致するようにすることです。これは、誰かが結果を認識せずに構造からメンバーを追加または変更するケースをキャッチします。はそれstatic_assertを拾ってユーザーに警告します。


3

概念がない場合、static_assertたとえばテンプレートで、単純で読みやすいコンパイル時の型チェックに使用できます。

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

// ...
}

2

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

Andrei AlexanderscuによるModern C ++ Designの第2章(セクション2.1)は、このようなコンパイル時アサーションのこのアイデアを実装しています

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

static_assert使用すると、delete次のようにキーワードの使用を禁止できます。

#define delete static_assert(0, "The keyword \"delete\" is forbidden.");

現代のすべてのC ++開発者は、クラス esとstruct s だけを使用して保守的なガベージコレクターを使用する場合、演算子newをオーバーロードして、保守的なガベージコレクターの保守的なヒープにメモリを割り当てる関数を呼び出すことを望みます。関数の最初でこれを行う関数を呼び出すことにより、初期化およびインスタンス化できますmain

たとえば、Boehm-Demers-Weiserの保守的なガベージコレクターを使用するすべての最新のC ++開発者は、main関数の冒頭で次のように記述します。

GC_init();

そして、すべてのにclassし、struct過負荷operator newをこのように:

void* operator new(size_t size)
{
     return GC_malloc(size);
}

そして今というoperator deleteベーム-デマーズ-ワイザー保守ガベージコレクタは両方自由に責任があるので、もはや必要とそれはもう必要がない場合、メモリのすべてのブロックの割り当てを解除されていない、開発者が禁止したいdeleteキーワードを。

1つの方法は、delete operatorこの方法でオーバーロードすることです。

void operator delete(void* ptr)
{
    assert(0);
}

しかし、これはお勧めできません。最近のC ++開発者はdelete operator、実行時に誤ってon /を呼び出したことがわかるためですが、コンパイル時にすぐに知っておくとよいでしょう。

したがって、私の意見では、このシナリオに対する最良の解決策はstatic_assert、この回答の冒頭に示されているを使用することです。

もちろん、これはまたして行うことができることBOOST_STATIC_ASSERTが、私はそれが思うstatic_assertよりよく、より常に優先されなければなりません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.