This is not possible outside the template!
From cppreference.com
Outside a template, a discarded statement is fully checked.
if constexpr
is not a substitute for the#if
preprocessing directive:void f() { if constexpr(false) { int i = 0; int *p = i; // Error even though in discarded statement } }
Any idea how to skip compilation of X2?
One option is to provide a template function for that.
template<typename T>
void test()
{
if constexpr (std::is_null_pointer_v<T>)
X2;
else
X1;
}
int main()
{
std::map<std::string, int> map;
test<decltype(map)>(); // now chooses the X1
}
Thanks to @HolyBlackCat and @MSalters. As they pointed out, the above solution is ill-formed NDR (therefore, compiling with MSVC compiler does not make any sense and on the other hand
the GCC and clang at least catch this by providing some compiler errors )
which has been detailed in the @HolyBlackCat’s,
answer!
Therefore can we skip the compilation of X2?
Unfortunately, NO as per your code!!
The preprocessor will be executed before the compilation of the translation unit.
Therefore one can not provide the type information (i.e. decltype(map)
) to #if
directives.
Hence for your case, there is no other way.
Good lessons from this post:
- Your program is, however, is a good example to avoid such kind macro
andconstexpr if
mixing. - Secondly, check the correctness of the code by different
compilers if possible!
I would suggest having a function overload for PP
(and of course there are many other ways) to your case, by which you could get a well-formed code:
See a demo.
#include <string>
#include <iostream>
#include <type_traits>
#include <map>
void pp(const std::string& str)
{
std::cout << str << std::endl;
}
template<typename... T> void pp(const T&... args)
{
// do something with args!
}
template<typename T>
constexpr void test()
{
if constexpr (std::is_null_pointer_v<T>)
pp("x", "x"); // call with args
else
pp("x"); // call with string
}