if / else at compile time in C++?

constexpr if
sfinae
static_if
c++11 compile time if
if constexpr c++11
if constexpr type check
c++ if statement
consider using if constexpr statement instead

Consider the following code :

#include <iostream>
#include <type_traits>

template<typename T> class MyClass
{
    public:
        MyClass() : myVar{0} {;}
        void testIf() {
            if (isconst) {
                myVar;
            } else {
                myVar = 3;
            }
        }
        void testTernary() {
            (isconst) ? (myVar) : (myVar = 3);
        }

    protected:
        static const bool isconst = std::is_const<T>::value;
        T myVar;
};

int main()
{
    MyClass<double> x;
    MyClass<const double> y;
    x.testIf();
    x.testTernary();
    y.testIf(); // <- ERROR
    y.testTernary(); // <- ERROR
    return 0;
}

For x (non-const) there is no problem. But y (const data type) cause an error even if the condition in if/else is known at compile-time.

Is there any possibility to not compile the false condition at compile-time ?

The simplest fix is partial template specialization:

template<typename T> class MyClassBase
{
    public:
        MyClassBase() : myVar{0} {;}

    protected:
        T myVar;
};

template<typename T> class MyClass: MyClassBase<T>
{
    public:
        void testIf() { myVar = 3; }
};

template<typename T> class MyClass<const T>: MyClassBase<const T>
{
    public:
        void testIf() { myVar; }
};

Another option is delegation:

template<typename T> class MyClass
{
    public:
        MyClass() : myVar{0} {;}
        void testIf() { testIf_impl(std::integral_constant<bool, isconst>()); }

    protected:
        static const bool isconst = std::is_const<T>::value;
        T myVar;

    private:
        void testIf_impl(std::true_type) { myvar; }
        void testIf_impl(std::false_type) { myVar = 3; }
};

SFINAE is another option, but is generally not preferred for this case:

template<typename T> class MyClass
{
    public:
        MyClass() : myVar{0} {;}
        template
        <typename U = void>
        typename std::enable_if<std::is_const<T>::value, U>::type testIf() { myvar; }
        template
        <typename U = void>
        typename std::enable_if<!std::is_const<T>::value, U>::type testIf() { myvar = 3; }

    protected:
        static const bool isconst = std::is_const<T>::value;
        T myVar;
};

Will those if statements be resolved at compile time?, In C++17 you can use constexpr if to make sure;. If you don't have access to C++ 17, there are still some SFINAE tricks (e.g. you can overload� When using ifelse if..else statements, there are few points to keep in mind − An if can have zero or one else's and it must come after any else if's. An if can have zero to many else if's and they must come before the else. Once an else if succeeds, none of the remaining else if's or else's will be tested. Syntax

C++17 if constexpr

Oh yes, it has arrived:

main.cpp

#include <cassert>
#include <type_traits>

template<typename T>
class MyClass {
    public:
        MyClass() : myVar{0} {}
        void modifyIfNotConst() {
            if constexpr(!isconst) {
                myVar = 1;
            }
        }
        T myVar;

    protected:
        static constexpr bool isconst = std::is_const<T>::value;
};

int main() {
    MyClass<double> x;
    MyClass<const double> y;
    x.modifyIfNotConst();
    y.modifyIfNotConst();
    assert(x.myVar == 1);
    assert(y.myVar == 0);
    return 0;
}

GitHub upstream.

Compile and run:

g++-8 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

See also: Difference between "if constexpr()" Vs "if()"

This will be really cool together with C++20 "string literal template arguments": Passing a string literal as a parameter to a C++ template class

Tested in Ubuntu 16.04, GCC 8.1.0.

constexpr if, The static-if for C++!. The feature allows you to discard branches of an if statement at compile-time based on a constant expression condition. if� The #if directive, with the #elif, #else, and #endif directives, controls compilation of portions of a source file. If the expression you write (after the #if) has a nonzero value, the line group immediately following the #if directive is kept in the translation unit.

You can specialize the class for const types

template<typename T>
class MyClass 
{
   // Whatever you need to do
};

template<typename T>
class MyClass<const T> 
{
   // Whatever you need to do for const types
};

7.7 Conditional Compilation (Compile-Time Decisions), HLA's compile-time language provides an IF statement, #IF, that lets you make a full expression syntax like you'd find in a high level language like C or Pascal. ___TIME___ It shows the current time as a character literal in “HH:MM:SS” format. ___STDC___ It is defined as 1 when the compiler complies with the ANSI standard. ___TIMESTAMP___ It is a sing literal in the form of “DDD MM YYYY Date HH:MM:SS”. It is used to specify the date and time of the last modification of the current source file.

The class template gets compiled for the given type. Even if the control flow doesn't get to the assignment, that assignment is compiled as well. Since the member is const, the compilation will fail.

You could use some form of SFINAE to skip that assignment, but it's not going to work as it is now.

This works(I've removed the testTernary member function for simplicity):

#include <iostream>
#include <type_traits>

template<typename T> class MyClass
{
    public:
        MyClass() : myVar{0} {;}

        template<class U = T>
        typename std::enable_if<std::is_const<U>::value>::type testIf() {
            myVar;
        }

        template<class U = T>
        typename std::enable_if<!std::is_const<U>::value>::type testIf() {
            myVar = 3;
        }

    protected:
        static const bool isconst = std::is_const<T>::value;
        T myVar;
};

int main()
{
    MyClass<double> x;
    MyClass<const double> y;
    x.testIf();
    y.testIf();
    return 0;
}

Simplify code with 'if constexpr' in C++17 - DEV, With C++17 we have an amazing way of writing compile time if statements. See how we can simplify code. Tagged with cpp, cpp17,� The feature allows you to discard branches of an if statement at compile-time based on a constant expression condition. if constexpr (cond) statement1; // Discarded if cond is false else statement2; // Discarded if cond is true. For example: template < typename T> auto get_value (T t) { if constexpr (std::is_pointer_v<T>) return *t; else return t; }

If the else branch weren't compiled, then your function would have a completely different meaning. You can't just not compile part of your code. If you don't want it to execute, don't write it. It's not like the function is compiled separately for each time it is called.

The whole point of a type system is to avoid accidentally trying to do things like assigning to const variables. You would have to write an entirely new (or overloaded) function that doesn't assign to that variable.

if statement - cppreference.com, where code needs to be executed based on a run-time or compile-time condition. attr(optional) if ( condition ) statement-true, (until C++17). on c++ 11. constexpr tells the compiler that this is a compile time constant, not allocated, used by value when needed and subject to optimizations, expressions involving constexpr and/or const values are calculated at compile time.

C++ Core Guidelines: Programming at Compile Time with constexpr , My mini-series about programming at compile time started with or full specialisation to perform conditional execution such as if statements. Compile time vs Runtime. Compile-time and Runtime are the two programming terms used in the software development. Compile-time is the time at which the source code is converted into an executable code while the run time is the time at which the executable code is started running. Both the compile-time and runtime refer to different types of

Simulate static_if with C++11/C++14, With recent compilers, if you have an if statement with a compile-time constant, it will never be executed at runtime and only the correct branch will� Compile-Time Errors Runtime-Errors; These are the syntax errors which are detected by the compiler. These are the errors which are not detected by the compiler and produce wrong results. They prevent the code from running as it detects some syntax errors. They prevent the code from complete execution.

The C Preprocessor: Conditionals, Modern compilers often do test if statements when a program is compiled, if their conditions are known not to vary at run time, and eliminate� When you compile your final binaries, define MY_COMPILER_ASSERT to be blank, so that its output isn't included in the result. Only define it the way you have it for debugging. But really, you aren't going to be able to catch every assertion this way. Some just don't make sense at compile time (like the assertion that a value is not null).

Comments