Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ check if statement can be evaluated constexpr

Is there a method to decide whether something can be constexpr evaluated, and use the result as a constexpr boolean? My simplified use case is as follows:

template <typename base> class derived {     template<size_t size>     void do_stuff() { (...) }      void do_stuff(size_t size) { (...) } public:     void execute()     {         if constexpr(is_constexpr(base::get_data())         {             do_stuff<base::get_data()>();         }         else         {             do_stuff(base::get_data());         }     } } 

My target is C++2a.

I found the following reddit thread, but I'm not a big fan of the macros. https://www.reddit.com/r/cpp/comments/7c208c/is_constexpr_a_macro_that_check_if_an_expression/

like image 979
Aart Stuurman Avatar asked Mar 21 '19 20:03

Aart Stuurman


People also ask

Is constexpr evaluated?

If you pass a non-constexpr argument to the PlusOne function, the compiler can't evaluate it at compile-time, and it will simply be a normal run-time function. Hint: "The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time."

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Is constexpr always evaluated at compile time?

constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well.

What is if constexpr?

Constexpr ifIf the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.


1 Answers

Here's another solution, which is more generic (applicable to any expression, without defining a separate template each time).

This solution leverages that (1) lambda expressions can be constexpr as of C++17 (2) the type of a captureless lambda is default constructible as of C++20.

The idea is, the overload that returns true is selected when and only when Lambda{}() can appear within a template argument, which effectively requires the lambda invocation to be a constant expression.

template<class Lambda, int=(Lambda{}(), 0)> constexpr bool is_constexpr(Lambda) { return true; } constexpr bool is_constexpr(...) { return false; }  template <typename base> class derived {     // ...      void execute()     {         if constexpr(is_constexpr([]{ base::get_data(); }))             do_stuff<base::get_data()>();         else             do_stuff(base::get_data());     } } 
like image 149
cpplearner Avatar answered Nov 09 '22 07:11

cpplearner