One possibility is to declare a name and then test for ::name
. To avoid the same name being declared in the global scope before a later use of the macro in the same translation unit, you can use __COUNTER__
, or __LINE__
if that works better for you. It's not perfect by any means, but at least the first line of the error contains the message. live example
#include <type_traits>
#define CONCAT(x, y) CONCAT_I(x, y)
#define CONCAT_I(x, y) x##y
#define ASSERT_FILESCOPE \
ASSERT_FILESCOPE_I(__COUNTER__)
#define ASSERT_FILESCOPE_I(counter) \
static constexpr bool CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)() { return true; } \
static_assert(::CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)(), "Detected a location other than file scope.")
I get this error from Clang:
main.cpp:17:5: error: no member named 'ASSERTION_FAILED_NOT_AT_FILE_SCOPE0' in the global namespace; did you mean simply 'ASSERTION_FAILED_NOT_AT_FILE_SCOPE0'?
ASSERT_FILESCOPE;
^~~~~~~~~~~~~~~~
main.cpp:7:5: note: expanded from macro 'ASSERT_FILESCOPE'
ASSERT_FILESCOPE_I(__COUNTER__)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:11:19: note: expanded from macro 'ASSERT_FILESCOPE_I'
static_assert(::CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)(), "Detected a location other than file scope.")
^~
main.cpp:17:5: note: 'ASSERTION_FAILED_NOT_AT_FILE_SCOPE0' declared here
main.cpp:7:5: note: expanded from macro 'ASSERT_FILESCOPE'
ASSERT_FILESCOPE_I(__COUNTER__)
^
main.cpp:10:20: note: expanded from macro 'ASSERT_FILESCOPE_I'
static constexpr bool CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)() { return true; } \
^
main.cpp:3:22: note: expanded from macro 'CONCAT'
#define CONCAT(x, y) CONCAT_I(x, y)
^
main.cpp:4:24: note: expanded from macro 'CONCAT_I'
#define CONCAT_I(x, y) x##y
^
<scratch space>:101:1: note: expanded from here
ASSERTION_FAILED_NOT_AT_FILE_SCOPE0
^
and this one from GCC:
main.cpp:11:19: error: '::ASSERTION_FAILED_NOT_AT_FILE_SCOPE0' has not been declared
static_assert(::CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)(), "Detected a location other than file scope.")
^
main.cpp:7:5: note: in expansion of macro 'ASSERT_FILESCOPE_I'
ASSERT_FILESCOPE_I(__COUNTER__)
^
main.cpp:17:5: note: in expansion of macro 'ASSERT_FILESCOPE'
ASSERT_FILESCOPE;
^
main.cpp:11:19: note: suggested alternative:
static_assert(::CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)(), "Detected a location other than file scope.")
^
main.cpp:7:5: note: in expansion of macro 'ASSERT_FILESCOPE_I'
ASSERT_FILESCOPE_I(__COUNTER__)
^
main.cpp:17:5: note: in expansion of macro 'ASSERT_FILESCOPE'
ASSERT_FILESCOPE;
^
main.cpp:10:34: note: 'foo::ASSERTION_FAILED_NOT_AT_FILE_SCOPE0'
static constexpr bool CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)() { return true; } \
^
main.cpp:4:24: note: in definition of macro 'CONCAT_I'
#define CONCAT_I(x, y) x##y
^
main.cpp:10:27: note: in expansion of macro 'CONCAT'
static constexpr bool CONCAT(ASSERTION_FAILED_NOT_AT_FILE_SCOPE, counter)() { return true; } \
^
main.cpp:7:5: note: in expansion of macro 'ASSERT_FILESCOPE_I'
ASSERT_FILESCOPE_I(__COUNTER__)
^
main.cpp:17:5: note: in expansion of macro 'ASSERT_FILESCOPE'
ASSERT_FILESCOPE;
^