Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
354 views
in Technique[技术] by (71.8m points)

c++ - "constexpr if" vs "if" with optimizations - why is "constexpr" needed?

C++1z will introduce "constexpr if" - an if that will have one of branches removed, based on the condition. Seems reasonable and useful.

However, is it not possible to do without constexpr keyword? I think that during compilation, compiler should know wheter condition is known during compilation time or not. If it is, even the most basic optimization level should remove unnecessary branch.

For example (see in godbolt: https://godbolt.org/g/IpY5y5):

int test() {
    const bool condition = true;
    if (condition) {
      return 0;
    } else {
      // optimized out even without "constexpr if"
      return 1;
    }
}

Godbolt explorer shows, that even gcc-4.4.7 with -O0 did not compile "return 1", so it achieved what was promised with constexpr if. Obviously such old compiler will not be able to do so when condition is result of constexpr function, but fact remains: modern compiler knows whether condition is constexpr or not and doesn't need me to tell it explicitly.

So the question is:

Why is "constexpr" needed in "constexpr if"?

question from:https://stackoverflow.com/questions/40972666/constexpr-if-vs-if-with-optimizations-why-is-constexpr-needed

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is easy to explain through an example. Consider

struct Cat { void meow() { } };
struct Dog { void bark() { } };

and

template <typename T>
void pet(T x)
{
    if(std::is_same<T, Cat>{}){ x.meow(); }
    else if(std::is_same<T, Dog>{}){ x.bark(); }
}

Invoking

pet(Cat{});
pet(Dog{});

will trigger a compilation error (wandbox example), because both branches of the if statement have to be well-formed.

prog.cc:10:40: error: no member named 'bark' in 'Cat'
    else if(std::is_same<T, Dog>{}){ x.bark(); }
                                     ~ ^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here
    pet(Cat{});
    ^
prog.cc:9:35: error: no member named 'meow' in 'Dog'
    if(std::is_same<T, Cat>{}){ x.meow(); }
                                ~ ^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here
    pet(Dog{});
    ^

Changing pet to use if constexpr

template <typename T>
void pet(T x)
{
    if constexpr(std::is_same<T, Cat>{}){ x.meow(); }
    else if constexpr(std::is_same<T, Dog>{}){ x.bark(); }
}

only requires the branches to be parseable - only the branch that matches the condition needs to be well-formed (wandbox example).

The snippet

pet(Cat{});
pet(Dog{});

will compile and work as expected.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...