static_assert(...)
( 'C ++ 11')が手元の問題をエレガントに解決する例を挙げていただけますか?
ランタイムに精通していassert(...)
ます。いつ私static_assert(...)
は通常よりも好むべきassert(...)
ですか?
また、boost
というものがありますがBOOST_STATIC_ASSERT
、それは同じstatic_assert(...)
ですか?
static_assert(...)
( 'C ++ 11')が手元の問題をエレガントに解決する例を挙げていただけますか?
ランタイムに精通していassert(...)
ます。いつ私static_assert(...)
は通常よりも好むべきassert(...)
ですか?
また、boost
というものがありますがBOOST_STATIC_ASSERT
、それは同じstatic_assert(...)
ですか?
回答:
頭の上から...
#include "SomeLibrary.h"
static_assert(SomeLibrary::Version > 2,
"Old versions of SomeLibrary are missing the foo functionality. Cannot proceed!");
class UsingSomeLibrary {
// ...
};
(C ++ライブラリで期待されるようSomeLibrary::Version
に)#define
d ではなく、静的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が小さすぎます:("
static_assert
が、非実行コンテキストに入れることはできますか?それはとても良い例のようです:)
static_assert
。プログラムが実行されるまで状態がわからない場合は、を使用しますassert
。
静的アサートは、コンパイル時にアサーションを作成するために使用されます。静的アサーションが失敗すると、プログラムはコンパイルされません。これは、たとえば、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
ます。
static_assert
特にC ++ 11から参照しようとしていませんでした。私のstatic_assert
上記の静的アサーションのほんの一部の抽象実装です。(私はCコードでそのようなものを個人的に使用しています)。私の回答は、静的アサーションの一般的な目的とランタイムアサーションとの違いについてのものです。
unsigned int
。これは規格によって保証されていません。タイプの変数は、unsigned int
32ビットのメモリを合法的に占有し、そのうちの16ビットを未使用のままにすることができます(したがって、マクロUINT_MAX
はに等しくなります65535
)。道だから、最初の静的アサーション(「記述unsigned int
オブジェクトが持つ誤解され、正確に32ビットを」)。説明と一致させるには、このアサーションも含める必要がありますstatic_assert(UINT_MAX >= 0xFFFFFFFFu)
。
私はそれを使用して、コンパイラの動作、ヘッダー、ライブラリ、さらには自分のコードについての私の想定が正しいことを確認します。たとえば、ここでは、構造体が期待されるサイズに正しくパックされていることを確認しています。
struct LogicalBlockAddress
{
#pragma pack(push, 1)
Uint32 logicalBlockNumber;
Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);
クラスの折り返しでstdio.h
のfseek()
、私はいくつかのショートカットを取ってきた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
が、標準化されており、より良いコンパイラ診断を提供する可能性があります。
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 ... */
};
上記の条件のいずれかが満たされていない場合、これによりコンパイル時エラーが発生します。
の用途の1つはstatic_assert
、構造(つまり、ネットワークやファイルなどの外界とのインターフェース)が、期待したサイズと正確に一致するようにすることです。これは、誰かが結果を認識せずに構造からメンバーを追加または変更するケースをキャッチします。はそれstatic_assert
を拾ってユーザーに警告します。
これは元の質問に直接答えるものではありませんが、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");
を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
よりよく、より常に優先されなければなりません。