3

私はstatic_assert(および標準化前のバリアントを)かなり頻繁に使用してきました。私たちの多くが使用していると確信している用途の 1 つは、機密データ構造のサイズがプラットフォームや構成全体で想定どおりに維持されるようにすることです。例えば:

class SizeSensitiveClass
{
    // ...
};

static_assert (sizeof(SizeSensitiveClass) == 18, "Check the size!");

ここで、この特定の用途に役立つ便利なマクロを作成しました。

#define STATIC_ASSERT_SIZE(T, sz)  (sizeof(T) == (sz), "Size of '" #T "' doesn't match the expected value.")

次のように使用します。

STATIC_ASSERT_SIZE (SizeSensitiveClass, 18);

この出力を生成するもの:(コンパイル時に、明らかにコンパイルエラーの形で)

「SizeSensitiveClass」のサイズが期待値と一致しません。

これは問題ありませんが、このマクロの実装を (インターフェイスをそのまま維持して) 拡張して、データ構造の現在のサイズ予想されるサイズも出力できるかどうか疑問に思っていました。理想的には、出力は次のようになります。

「SizeSensitiveClass」のサイズが期待値と一致しません (20 対 18)。

今のサイズでも非常に便利です。これは可能ですか?

VC12 (Visual C++ 2013) と GCC 4.8.1 を使用しています。少なくともこれら2つに移植できるソリューション/テクニック/方法をいただければ幸いです。

私は一般的な「文字列化」トリックを試しましたが、うまくいきませんでした (期待していたように) sizeof(T)、出力にリテラル文字列が生成されるだけです。

これが s (メッセージ文字列を生成するため)を使用して実装される可能性があるという漠然とした考えがありますconstexprが、私はそれらに慣れていません。

4

3 に答える 3

8

これは、あなたが想像している意味では解決策ではないかもしれませんが、実際のサイズと予想されるサイズを常に含むエラー メッセージが生成され、次のエラー メッセージを閉じますstatic_assert

#include <type_traits>

template< typename Type, std::size_t ExpectedSize, std::size_t ActualSize = 0 >
struct validate_size : std::true_type
{
    static_assert( ActualSize == ExpectedSize,
                   "actual size does not match expected size" );
};

template< typename Type, std::size_t ExpectedSize >
struct validate_size< Type, ExpectedSize, 0 >
  : validate_size< Type, ExpectedSize, sizeof( Type ) >
{};

int main()
{
    static_assert( validate_size< int, 4 >::value, "Oops" );
    static_assert( validate_size< int, 5 >::value, "Oops2" );
}

GCC 4.8 からのエラー メッセージ:

main.cpp: In instantiation of 'struct validate_size<int, 5ul, 4ul>':
main.cpp:10:8:   required from 'struct validate_size<int, 5ul>'
main.cpp:15:43:   required from here
main.cpp:6:5: error: static assertion failed: actual size does not match expected size
     static_assert( ActualSize == ExpectedSize, "actual size does not match expected size" );
     ^

Clang からのメッセージには、<int, 5ul, 4ul>-part も含まれています。自分で VS を確認してください。

実際の例

更新:そして、明らかにインターフェースをそのまま維持できます:

#define STATIC_ASSERT_SIZE(T, sz) static_assert(validate_size<T,sz>::value, "")
于 2013-10-31T07:49:42.707 に答える
2

Stringize は、予想されるサイズで機能するはずです。#szで使用すると、"18"(または渡した任意の数値リテラル) に展開されSTATIC_ASSERT_SIZEます。

リテラルの代わりに18別の名前を渡す場合、文字列化する前にマクロ展開するために二重文字列化トリック#defineが必要になります。sz

sizeof(T)残念ながら、プリプロセッサは の値を認識していないstatic_assertため、文字列リテラルを受け取る必要があります。私は何かが欠けているかもしれませんが、あなたは運が悪いと思います。

于 2013-10-31T01:41:13.780 に答える
1

できます。C++ テンプレート プログラミングを参照してください。テンプレート para が size(T) の値を持つ整数であるテンプレート クラスを作成します。アサーションが失敗した場合、クラスにコンパイラ エラーを発生させます。コンパイラは、サイズ (T) の値を取得できるクラス名を出力します。

于 2013-10-31T02:28:36.300 に答える