constexpr if

Contents[Show]

In today's post, I want to introduce a very interesting C++17 feature: constexpr if. constexpr if enables it to conditionally compile source code and can also be used for nice tricks at compile time.

 

constexprIf

Introducing constexpr if is straightforward.

template <typename T>
auto getValue(T t) {
    if constexpr (std::is_pointer_v<T>)      // (1)
        return *t; // deduces return type to int for T = int*
    else                                     // (2)
        return t;  // deduces return type to int for T = int
}

 

The code snippet shows one interesting fact about constexpr if: Although it is called constexpr if, it is used as if constexpr: if constexpr (std::is_pointer_v<T>).

If T is a pointer, the if branch in line (1) will be compiled. If not, the else branch in line (2). Two points are important to mention. The function getValue has two different return types and both branches of the if the statement have to be valid.

The expression in constexpr if has to be a compile time predicate. A compile time predicate is a function that returns a boolean and runs at compile time. I used in the code snippet a function from the type-traits library. Alternatively, in C++20 you can use a concept. Here is the equivalent example using the concept std::integral:

template <typename T>
auto get_value(T t) {
    if constexpr (std::integral<T>)          // (1)
        return *t; // deduces return type to int for T = int*
    else                                     // (2)
        return t;  // deduces return type to int for T = int
}

 

I see, the two code snippets are not so impressive. Let me continue with template metaprogramming.

Thanks to constexpr if, template metaprogramming often easier to write and read.

Template Metaprogramming with constexpr if

Metaprogramming is programming on programs. C++ applies metaprogramming at compile time. It started in C++98 with template metaprogramming, was formalized in C++11 with the type-traits library, and since C++11 has steadily improved.

Here is the "Hello World" of template metaprogramming: calculating the factorial of a number:

// factorial.cpp

#include <iostream>

template <int N>                                                                 // (2)
struct Factorial{
    static int const value = N * Factorial<N-1>::value;
};

template <>                                                                      // (3)
struct Factorial<1>{
    static int const value = 1;
};

int main(){
    
    std::cout << '\n';
    
    std::cout << "Factorial<5>::value: " << Factorial<5>::value << '\n';    // (1)
    std::cout << "Factorial<10>::value: " << Factorial<10>::value << '\n';  // (4)
    
    std::cout << '\n';

}

 

The call factorial<5>::value (line 1) causes the instantiation of the primary or general template (line 2). During this instantiation, Factorial<4>::value will be instantiated. This recursion will end if the fully specialized class template Factorial<1> kicks in (line 3).

If you want to know more about template metaprogramming, read my previous posts:

  1. Template Metaprogramming - How it All Started
  2. Template Metaprogramming - How it Works
  3. Template Metaprogramming - Hybrid Programming

Let me rewrite the program using constexpr if:

// factorialConstexprIf.cpp

template <int N>                                              // (1)
struct Factorial{
    static int const value = N * Factorial<N-1>::value;
};

template <>                                                   // (2)
struct Factorial<1>{
    static int const value = 1;
};

template <int N>                                              // (3)
constexpr int factorial() {
    if constexpr (N >= 2) 
        return N * factorial<N-1>();
    else 
        return N;
}

int main(){
    
    static_assert(Factorial<5>::value == factorial<5>());     // (4)             
    static_assert(Factorial<10>::value == factorial<10>());   // (4)

}

 

The primary template of Factorial (line 1) becomes the if condition in the constexpr function factorial (line 3), and the full specialization of Factorial for 1 (line 2) becomes the else case in the constexpr function factorial (line 3). Of course, the class template Factorial and the constexpr function factorial return the same result and are executed at compile time (line 4). To make it short, I prefer the constexpr function using constexpr if because it reads almost such as a usual function.

Let's do it once more. Here is the infamous Fibonacci function based template metaprogramming (Fibonacci) and constexpr if (fibonacci).

// fibonacciConstexprIf.cpp

template<int N>
constexpr int fibonacci()
{
    if constexpr (N>=2)
        return fibonacci<N-1>() + fibonacci<N-2>();
    else
        return N;
}

template <int N>                                                  // (1)            
struct Fibonacci{
    static int const value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};

template <>                                                      // (2)                
struct Fibonacci<1>{
    static int const value = 1;
};

template <>                                                      // (3)                
struct Fibonacci<0>{
    static int const value = 0;
};

int main() {

    static_assert(fibonacci<7>() == 13);
    static_assert(fibonacci<7>() == Fibonacci<7>::value);
    
}

 

The constexpr function fibonacci is straightforward to read. The entire functionality is in one function body. In contrast, the template metaprogram Fibonacci requires the three classes. The primary template (line 1) and the two full specializations for the values 1 and 0 (lines 2 and 3).

More Information about my Mentoring Program "Fundamentals for C++ Professionals"

I created the platform for my new mentoring on https://www.modernescpp.org/. You can skip through each of the 28 lessons. I also presented the 6th lesson about move semantics and perfect forwarding in the post 'More Information about my Mentoring Program "Fundamentals for C++ Professionals"'. Here are the next steps before I start the mentoring program.

  • Beginning of March: online information session about my mentoring program, where you can also ask your questions
  • Middle of March: my mentoring program opens for registration
  • April: the registration for the mentoring program closes, and the mentoring program starts

If you want to stay informed, write an e-mail to This email address is being protected from spambots. You need JavaScript enabled to view it. with the subject "Mentoring". Write me also an e-mail if you need more information.

What's Next?

Templates are a powerful tool and, therefore, provide new design choices. In my next post, I write about static and dynamic polymorphism.

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Ralf Holly, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, and Stephen Totten.

 

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, Ralf Abramowitsch, John Nebel, and Mipko.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

Mentoring Program in English

Do you want to stay informed about my mentoring programs? Write to This email address is being protected from spambots. You need JavaScript enabled to view it..

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

New

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Comments   

0 #1 Ralf 2022-03-15 15:27
But in practice, one would implement 'fibonacci' as a regular constexpr function (no template, no constexpr if), right?
Quote

Mentoring: Fundamentals for C++ Professionals

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 4968

Yesterday 8916

Week 13884

Month 64231

All 10004478

Currently are 183 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments