131

static_assert(...)('C++11') が手の問題をエレガントに解決する例を教えてください。

私はランタイムに精通していassert(...)ます。static_assert(...)通常よりも優先するのはいつassert(...)ですか?

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

4

8 に答える 8

146

静的アサートは、コンパイル時にアサーションを作成するために使用されます。静的アサーションが失敗すると、プログラムはコンパイルされません。これは、さまざまな状況で役立ちます。たとえば、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

于 2009-10-30T03:47:42.820 に答える
89

私の頭の上から...

#include "SomeLibrary.h"

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

class UsingSomeLibrary {
   // ...
};

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

コードを実際にコンパイル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 が小さすぎます :(」
于 2009-10-30T03:43:44.663 に答える
14

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

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標準化されており、より優れたコンパイラ診断を提供する可能性がありますが、意図は同じです。

于 2009-10-30T03:46:54.680 に答える
10

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 ... */
};

上記の条件のいずれかが満たされない場合、コンパイル時エラーが発生します。

于 2010-01-12T12:18:36.043 に答える
8

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

于 2009-10-30T03:43:31.253 に答える
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");

// ...
}
于 2015-09-14T20:54:39.640 に答える
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");
于 2014-06-02T03:47:45.703 に答える