Reputation: 433
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?
Upvotes: 5
Views: 151
Reputation: 51845
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.
Upvotes: 1
Reputation: 172934
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 } }
Upvotes: 5
Reputation: 29985
std::min
works with references. And both the arguments should be the same type. Since you're providing 2 different types, it cannot decide which one the argument type should be. You can work around that by explicitly specifying the type you like both the arguments to be converted:
std::min<double>(static_cast<int64_t>(2), x)
Be careful with dangling references.
The case when the failing branch of if constexpr
doesn't matter is only in templates and f
is not a template function.
Upvotes: 0