I'm testing the code below:
#define TO_STRING(X) #X
#define TEST(X, Y) namespace Y { constexpr std::string_view name{#X}, raw_value{TO_STRING(X)};\
constexpr bool defined {name!=raw_value}; constexpr bool has_value{raw_value!=""}; }
#define A
#define B 1
TEST(A, a);
TEST(B, b);
TEST(C, c);
int main()
{
if constexpr (a::defined && a::has_value) {
std::cout << a::name << " = " << a::raw_value << '\n';
} else {
std::cout << a::name << " not defined or have no value\n";
}
if constexpr (b::defined && b::has_value) {
std::cout << b::name << " = " << b::raw_value << '\n';
} else {
std::cout << b::name << " not defined or have no value\n";
}
if constexpr (c::defined && c::has_value) {
std::cout << c::name << " = " << c::raw_value << '\n';
} else {
std::cout << c::name << " not defined or have no value\n";
}
return 0;
}
Which produces the following output:
A not defined or have no value B = 1 C not defined or have no value
If I modify the TEST
adding a new function:
#define TEST(X, Y) namespace Y { constexpr std::string_view name{#X}, raw_value{TO_STRING(X)};\
constexpr bool defined {name!=raw_value}; constexpr bool has_value{raw_value!=""};\
constexpr auto value() { if constexpr (defined && has_value) return X; else return; } }
I was expecting the compiler to ignore the return X
statement while expanding TEST(C, c)
macro, it reports an error instead:
error: use of undeclared identifier 'C' TEST(C, c); ^
Referencing an undeclared identifier is absolutely ill formed but I was expecting the compiler to ignore it because I thought that if constexpr
untaken branches didn't need to be well formed. Is there a way to achieve this behaviour?