Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does min still complain inside constexpr?

I have the following code snippet:

#include <iostream>
#include <type_traits>
#include <algorithm>
#include <cstdint>
using T = double;

int main()
{
    f();
}
void f() {
    T x = 2;
    if constexpr(std::is_integral_v<T>)
    {
        std::cout << std::min(static_cast<int64_t>(2), x);
    } else {
    std::cout << std::min(1.0, x);
    }
}

The compiler is explaining that

<source>:15:57: error: no matching function for call to 'min(int64_t, T&)'

I thought it wouldn't be a problem because when T is a double, the first branch won't be instantiated. Apparently my understanding is wrong. Could someone help point out where my understanding goes wrong?

like image 582
user122049 Avatar asked Mar 08 '21 09:03

user122049


People also ask

Is std :: max constexpr?

std::min and std::max are constexpr in C++14, which obviously means there isn't a good reason (these days) not to have them constexpr.

Is not usable as a constexpr function?

It means that compiler makes most general assumptions when compiling this function. And this assumption is that arguments are non-compile-time. It means that compiler can't guarantee that your if-constexpr is always compile-time, hence the error about it.


2 Answers

You need to make f() template, and T template parameter.

template <typename T>
void f() {
    T x = 2;
    if constexpr(std::is_integral_v<T>)
    {
        std::cout << std::min(static_cast<int64_t>(2), x);
    } else {
    std::cout << std::min(1.0, x);
    }
}

then

int main()
{
    f<double>();
}

For constexpr if:

(emphasis mine)

If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated .

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive:

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // Error even though in discarded statement
    }
}
like image 58
songyuanyao Avatar answered Oct 17 '22 02:10

songyuanyao


Outside of a template, the "false" branch of a constexpr if clause is discarded, not ignored. Thus, the code in such a branch must still be well-formed (and yours isn't, for the reason given).

From cppreference:

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive.

like image 31
Adrian Mole Avatar answered Oct 17 '22 03:10

Adrian Mole