1. ホーム
  2. c++

static_warning は存在しますか?

2023-09-14 05:35:15

質問

私が知っているのは この質問 でBoostの"STATIC WARNING"について触れていますが、具体的にどのように実装すればいいのか、改めて質問したいと思います。 static_warning と同じように動作する static_assert と同じように動作しますが 警告 を出すだけで、コンパイル時のエラーは発生しません。

私は、C++11 以前の Alexandrescu の静的アサートの提案に似たものを希望します。それは、エラーの一部として、何らかの有用な文脈情報を表示することに成功しました。

この構造が機能するために、ユーザーが特定の標準的なコンパイラー警告を有効にすることを要求することは許容されるでしょう (おそらく "invalid pointer conversion" または "breaks strict aliasing rules")。-- いずれにせよ通常のコンパイルの一部であるべきあらゆる警告を使用することができます。

要するに、私は static_warning(false, "Hello world"); を使用して、警告メッセージに文字列 "hello world" を含むコンパイラ警告を作成する必要があります。これは、例えば GCC や MSVC で可能ですか、そしてどのように可能ですか?

私は喜んで、特に賢い解決策に小さな報酬の賞金を出します。


少し説明します。このアイデアを思いついたのは この質問 : 静的警告は、複雑なテンプレート特殊化のコンパイルプロセスをトレースするのに便利な方法です。静的警告は、コンパイラが "コードのこの部分を今コンパイルしています." を発するための単純なビーコンとして使用できます。


更新しました。 理想的には、以下のような設定で警告が発生することです。

template <typename T> struct Foo
{
    static_warning(std::is_pointer<T>::value, "Attempting to use pointer type.");
    // ...
};

int main() { Foo<int> a; Foo<int*> b; }

どのように解決するのですか?

Michael Eのコメントを引用しています。

#if defined(__GNUC__)
#define DEPRECATE(foo, msg) foo __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
#define DEPRECATE(foo, msg) __declspec(deprecated(msg)) foo
#else
#error This compiler is not supported
#endif

#define PP_CAT(x,y) PP_CAT1(x,y)
#define PP_CAT1(x,y) x##y

namespace detail
{
    struct true_type {};
    struct false_type {};
    template <int test> struct converter : public true_type {};
    template <> struct converter<0> : public false_type {};
}

#define STATIC_WARNING(cond, msg) \
struct PP_CAT(static_warning,__LINE__) { \
  DEPRECATE(void _(::detail::false_type const& ),msg) {}; \
  void _(::detail::true_type const& ) {}; \
  PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());} \
}

// Note: using STATIC_WARNING_TEMPLATE changes the meaning of a program in a small way.
// It introduces a member/variable declaration.  This means at least one byte of space
// in each structure/class instantiation.  STATIC_WARNING should be preferred in any 
// non-template situation.
//  'token' must be a program-wide unique identifier.
#define STATIC_WARNING_TEMPLATE(token, cond, msg) \
    STATIC_WARNING(cond, msg) PP_CAT(PP_CAT(_localvar_, token),__LINE__)

このマクロは名前空間、構造体、関数スコープで呼び出すことができます。 入力が与えられると

#line 1
STATIC_WARNING(1==2, "Failed with 1 and 2");
STATIC_WARNING(1<2, "Succeeded with 1 and 2");

struct Foo
{
  STATIC_WARNING(2==3, "2 and 3: oops");
  STATIC_WARNING(2<3, "2 and 3 worked");
};

void func()
{
  STATIC_WARNING(3==4, "Not so good on 3 and 4");
  STATIC_WARNING(3<4, "3 and 4, check");
}

template <typename T> struct wrap
{
  typedef T type;
  STATIC_WARNING(4==5, "Bad with 4 and 5");
  STATIC_WARNING(4<5, "Good on 4 and 5");
  STATIC_WARNING_TEMPLATE(WRAP_WARNING1, 4==5, "A template warning");
};

template struct wrap<int>;

GCC 4.6 (デフォルトの警告レベル)で生成されます。

static_warning.cpp: コンストラクタ 'static_warning1::static_warning1()' にて。
static_warning.cpp:1:1: 警告: 'void static_warning1::_(const detail::false_type&)' は非推奨です(static_warning1::false_type&)。
    は非推奨です (static_warning.cpp:1 で宣言されています)。


1 と 2 で失敗しました


 [-Wdeprecated-declarations]です。
static_warning.cpp: コンストラクタ 'Foo::static_warning6::static_warning6()' 内にあります。
static_warning.cpp:6:3: 警告: 'void Foo::static_warning6::_(const detail::false_type&)' は非推奨です。
    は非推奨です (static_warning.cpp:6 で宣言されています)。


2 と 3: oops


 [-Wdeprecated-declarations](廃止予定)。
static_warning.cpp: コンストラクタ 'func()::static_warning12::static_warning12()' 内にあります。
static_warning.cpp:12:3: 警告: 'void func()::static_warning12::_(const detail::false_type&)' は非推奨です。
    は非推奨です (static_warning.cpp:12 で宣言されています)。


3 と 4 ではあまり良くない


 [-Wdeprecated-declarations](非推奨)。
static_warning.cpp: コンストラクタ 'wrap<T>::static_warning19::static_warning19() [with T = int]' 内にあります。
static_warning.cpp:24:17: ここからインスタンス化されました。
static_warning.cpp:19:3: 警告: 'void wrap<T>::static_warning19::_(const detail::false_type&) [with T = int]' は非推奨です。
    は非推奨です (static_warning.cpp:19 で宣言されています)。


4 と 5 と相性が悪い


 [-Wdeprecated-declarations]です。

Visual C++ 2010 (/W3 以上) では、次のように書かれています。

warnproj.cpp(1): 警告 C4996: 'static_warning1::_': 1 と 2 で失敗
warnproj.cpp(1) : 'static_warning1::_' の宣言を参照してください。
warnproj.cpp(6) : 警告 C4996: 'Foo::static_warning6::_': 2 と 3 で失敗: oops
warnproj.cpp(6) : 'Foo::static_warning6::_' の宣言を参照。
warnproj.cpp(12) : 警告 C4996: 'func::static_warning12::_': 3 と 4 であまり良くない
warnproj.cpp(12) : 'func::static_warning12::_' の宣言を参照。
warnproj.cpp(19): 警告 C4996: 'wrap<T>::static_warning19::_': 4 と 5 で悪い
    と共に
    [
        T=int
    ]
warnproj.cpp(19) : 'wrap<T>::static_warning19::_' の宣言を参照してください。
    と共に
    [
        T=int
    ]
warnproj.cpp(19) : クラステンプレートメンバー関数 'wrap<T>::static_warning19::static_warning19(void)' をコンパイル中。
    と共に
    [
        T=int
    ]
warnproj.cpp(24) : コンパイル中のクラス・テンプレートのインスタンス化 'wrap<T>::static_warning19' への参照を参照してください。
    で
    [
        T=int
    ]


Linux上のClang++ 3.1は、間違いなくより美しい出力を生成します(色は表示されません)。

tst3.cpp:1:1: 警告: '_'は非推奨です。1 と 2 で失敗
      [-Wdeprecated-declarations]です。
STATIC_WARNING(1==2, "Failed with 1 and 2")です。
^
tst3.cpp:24:38: note: マクロ 'STATIC_WARNING' から展開されました。
  PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());}; }. \
                                     ^
tst3.cpp:6:3: 警告: '_' は非推奨です。2と3: oops
      [-Wdeprecated-declarations]です。
  STATIC_WARNING(2==3, "2 and 3: oops")です。
  ^
tst3.cpp:24:38: note: マクロ 'STATIC_WARNING' から展開されました。
  PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());}; }. \
                                     ^
tst3.cpp:12:3: warning: '_' は非推奨です。3と4ではあまりよろしくない
      [-Wdeprecated-declarations]です。
  STATIC_WARNING(3==4, "Not so good on 3 and 4")を参照してください。
  ^
tst3.cpp:24:38: note: マクロ 'STATIC_WARNING' から展開されました。
  PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());}; }. \
                                     ^
tst3.cpp:19:3: 警告: '_' は非推奨です。4,5と相性が悪い
      [となります。]
  STATIC_WARNING(4==5, "Bad with 4 and 5")です。
  ^
tst3.cpp:24:38: note: マクロ 'STATIC_WARNING' から展開されました。
  PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());}; }. \
                                     ^
tst3.cpp:23:17: note: メンバー関数のインスタンス化において
      wrap<int>::static_warning19::static_warning19' のインスタンス化において、ここで要求されます。
テンプレート構造体 wrap<int>
                ^
4つの警告が発生しました。