Reproduction of commentary by 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__)
A macro can be invoked in a namespace, structure, and region. Given input:
#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 (at the default warning level) produces:
static_warning.cpp: In constructor 'static_warning1 :: static_warning1 ()':
static_warning.cpp: 1: 1: warning: 'void static_warning1 :: _ (const detail :: false_type &)'
is deprecated (declared at static_warning.cpp: 1): Failed with 1 and 2 [-Wdeprecated-declarations]
static_warning.cpp: In constructor 'Foo :: static_warning6 :: static_warning6 ()':
static_warning.cpp: 6: 3: warning: 'void Foo :: static_warning6 :: _ (const detail :: false_type &)'
is deprecated (declared at static_warning.cpp: 6): 2 and 3: oops [-Wdeprecated-declarations]
static_warning.cpp: In constructor 'func () :: static_warning12 :: static_warning12 ()':
static_warning.cpp: 12: 3: warning: 'void func () :: static_warning12 :: _ (const detail :: false_type &)'
is deprecated (declared at static_warning.cpp: 12): Not so good on 3 and 4 [-Wdeprecated-declarations]
static_warning.cpp: In constructor 'wrap <T> :: static_warning19 :: static_warning19 () [with T = int]':
static_warning.cpp: 24: 17: instantiated from here
static_warning.cpp: 19: 3: warning: 'void wrap <T> :: static_warning19 :: _ (const detail :: false_type &) [with T = int]'
is deprecated (declared at static_warning.cpp: 19): Bad with 4 and 5 [-Wdeprecated-declarations]
While Visual C ++ 2010 (at / W3 or higher) says:
warnproj.cpp (1): warning C4996: 'static_warning1 :: _': Failed with 1 and 2
warnproj.cpp (1): see declaration of 'static_warning1 :: _'
warnproj.cpp (6): warning C4996: 'Foo :: static_warning6 :: _': 2 and 3: oops
warnproj.cpp (6): see declaration of 'Foo :: static_warning6 :: _'
warnproj.cpp (12): warning C4996: 'func :: static_warning12 :: _': Not so good on 3 and 4
warnproj.cpp (12): see declaration of 'func :: static_warning12 :: _'
warnproj.cpp (19): warning C4996: 'wrap <T> :: static_warning19 :: _': Bad with 4 and 5
with
[
T = int
]
warnproj.cpp (19): see declaration of 'wrap <T> :: static_warning19 :: _'
with
[
T = int
]
warnproj.cpp (19): while compiling class template member function 'wrap <T> :: static_warning19 :: static_warning19 (void)'
with
[
T = int
]
warnproj.cpp (24): see reference to class template instantiation 'wrap <T> :: static_warning19' being compiled
with
[
T = int
]
Clang ++ 3.1 on Linux gives a nicer result (color not shown):
tst3.cpp: 1: 1: warning: '_' is deprecated: Failed with 1 and 2
[-Wdeprecated-declarations]
STATIC_WARNING (1 == 2, "Failed with 1 and 2");
^
tst3.cpp: 24: 38: note: expanded from macro 'STATIC_WARNING'
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp: 6: 3: warning: '_' is deprecated: 2 and 3: oops
[-Wdeprecated-declarations]
STATIC_WARNING (2 == 3, "2 and 3: oops");
^
tst3.cpp: 24: 38: note: expanded from macro 'STATIC_WARNING'
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp: 12: 3: warning: '_' is deprecated: Not so good on 3 and 4
[-Wdeprecated-declarations]
STATIC_WARNING (3 == 4, "Not so good on 3 and 4");
^
tst3.cpp: 24: 38: note: expanded from macro 'STATIC_WARNING'
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp: 19: 3: warning: '_' is deprecated: Bad with 4 and 5
[-Wdeprecated-declarations]
STATIC_WARNING (4 == 5, "Bad with 4 and 5");
^
tst3.cpp: 24: 38: note: expanded from macro 'STATIC_WARNING'
PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
^
tst3.cpp: 23: 17: note: in instantiation of member function
'wrap <int> :: static_warning19 :: static_warning19' requested here
template struct wrap <int>
^
4 warnings generated.