Why does this usage of C++17 if constexpr fail?

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
    and constexpr 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
}

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)