Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"If constexpr" in C++17 does not work in a non-templated function

Tags:

I tried to play with the C++17 standard. I tried to use one of the features of C++17 if constexpr. And I had a problem... Please take a look at the following code. This compiles without errors. In the following code, I tried to use if constexpr to check if it is a pointer.

#include <iostream> #include <type_traits>  template <typename T> void print(T value) {   if constexpr (std::is_pointer_v<decltype(value)>)     std::cout << "Ptr to " << *value << std::endl; // Ok   else     std::cout << "Ref to " << value << std::endl; }  int main() {   auto n = 1000;   print(n);   print(&n); } 

But when I rewrite the above code, as shown below, where if constexpr is in the main function:

#include <iostream> #include <type_traits>  int main() {   auto value = 100;   if constexpr (std::is_pointer_v<decltype(value)>)     std::cout << "Ptr to " << *value << std::endl; // Error   else     std::cout << "Ref to " << value << std::endl; } 

I get a compilation error:

main.cpp:8:32: error: invalid type argument of unary ‘*’ (have ‘int’)  std::cout << "Ptr to " << *value << std::endl; 

Problem is not in the main function. This can be any function similar to the following.

void print() {   auto value = 100;   if constexpr (std::is_pointer_v<decltype(value)>)     std::cout << "Ptr to " << *value << std::endl; // Error   else     std::cout << "Ref to " << value << std::endl; }  int main() {   print(); } 

I would like to know why if constexpr works only in template functions, even if the type is deduced by the decltype from the input parameter.

like image 923
NYM Avatar asked Apr 26 '18 20:04

NYM


People also ask

What is the point of constexpr functions?

constexpr functions A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.

What is if constexpr?

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

What is false constexpr?

Short answer: static_assert(false) should never appear in a constexpr if expression, regardless of whether it's in a template function or whether it's in the discarded branch.


2 Answers

I would like to know why "if constexpr" works only in template functions, even if the type is deduced by the decltype from the input parameter.

This is by design.

if constexpr will not instantiate the branch not taken if it's within a template. It won't just treat the branch not taken as token soup and avoid parsing it or performing semantic analysis entirely. Both sides are still going to be analyzed, and since *value is ill-formed for ints, that's an error.

You simply can't use if constexpr to avoid compiling non-template code. It's only to avoid instantiating template code that's potentially invalid-for-the-particular-specialization.

like image 137
Barry Avatar answered Oct 10 '22 06:10

Barry


C++ standard, clause 9.4.1:

If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool (8.6); this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity (Clause 17), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.

(emphasis mine)

So, a substatement of a constexpr if still gets instantiated if it is not inside a template, thus it must at least compile.

like image 33
lisyarus Avatar answered Oct 10 '22 04:10

lisyarus