Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is std::swap allowed in this constexpr function?

Tags:

c++

c++17

I wrote a function calculating the gcd of two numbers which uses std::swap in the case where the second parameter is greater than the first.

Some time later, I realised that std::swap is not constexpr, but my function still compiled and ran successfully.
I tried with MinGW-w64 8.1.0 and Visual C++ 2017 and it worked for both.

My first thought was that's because constexpr functions are allowed to be executed at runtime, so I tried std::integral_constant<int,gcd(32,12)>, and it worked.

However, I cannot use any of my own non-constexpr function (which is what I expect).

Here is my test code :

#include <utility>

inline void foo() noexcept {
}

template<typename T>
constexpr T gcd(T a, T b) {
    // foo();            // only works with non-constexpr j
    if(a<b) {
        std::swap(a, b); // works for both constexpr i and non-constexpr j
    }
    if(b==0) {
        return a;
    } else {
        return gcd(b, a%b);
    }
}

int main()
{
    constexpr int i = std::integral_constant<int, gcd(32, 12)>::value;
    int j = gcd(32,12);
}

So, my question is : why can I use std::swap in my function ?

like image 880
Annyo Avatar asked Mar 11 '19 09:03

Annyo


1 Answers

Here is a relevant quote from cppreference:

A constexpr function must satisfy the following requirements:

  • ...
  • there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression

There is a path that does not go through std::swap(), where a a>=b. In fact, for gcd(32, 12) the execution never goes through std::swap().

EDIT: I had a look at the C++14 draft. Section 7.1.5 The constexpr specifier. Paragraph 5 says:

For a non-template, non-defaulted constexpr function [...], if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.20), or, for a constructor, a constant initializer for some object (3.6.2), the program is ill-formed;

and the example they give is:

constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
like image 160
Michael Veksler Avatar answered Nov 15 '22 07:11

Michael Veksler