I'd like to be able to conditionally declare a variable constexpr, according to properties of its initializer.
My actual use case is a bit complicated but it can be summarized to:
#include <cmath>
#include <type_traits>
template<typename T>
constexpr double create_val(T x)
{
// some code that can be constant evaluated or not, according to T
}
int main() {
constexpr_if_possible auto v = create_val(4);
// w can only be constexpr under certain conditions
// otherwise it should be at least const
constexpr_if_possible auto w = create_val(4.0);
return static_cast<int>(v*w);
}
where constexpr_if_possible
would actually mean constexpr
when the expression can be constant evaluated, and be const
otherwise.
Here is an example to illustrate this:
#include <cmath>
#include <type_traits>
template<typename T>
constexpr double create_val(T x)
{
static_assert(std::is_arithmetic_v<T>);
if constexpr (std::is_integral_v<T>)
{
// some leggit code in constant expression
// only an example
return static_cast<double>(x*x);
}
else
{
// some not usable code in constant expression
// only an example
return std::sqrt(x);
}
}
int main() {
// constexpr_if_possible is equivalent to constexpr here
constexpr auto v = create_val(4);
// conditions are not met, constexpr_if_possible is equivalent to const
const auto w = create_val(4.0);
return static_cast<int>(v*w);
}
clang and msvc would rightfully reject this code with constexpr w
due to the use of the non-constexpr
function std::sqrt
.
(gcc accepts it and optimizes away the computation, probably because it already declares std::sqrt
as constexpr
).
Live
According to the template argument of create_val
, the initialized variable can or cannot be constexpr
.
If I were in a template function I could use if constexpr
but, perhaps, at the price of code duplication.
Obviously, I could also read all the codes to determine "manually" if constant evaluation is possible but, as seen in my example, when I'll change language standard, I'll have to parse again all my code to see if situation has changed.
Is it possible (and how) to declare v
, w
conditionally constexpr with respect to their initializer? In pseudo-totally-incorrect code:
constexpr_if_possible auto w = create_val(...);
(thanks to @Jarod42 for having help me to formulate constexpr_if_possible
)
I've got the impression that the language syntax cannot allow for this but would there be some workaround?
NB In real use case, my variable type can be anything (fundamental types as well as classes).
You want a "constexpr_if_possible".
It is what const
does for integral types only (inherited from C++98, when constexpr
didn't exist). i.e const int x = 42;
is equivalent to constexpr int x = 42;
whereas const int y = read_int_from(std::cin);
is not constexpr
.
const
might be good enough for non-integral types, compiler would probably optimize it.
For those types, they couldn't be used as NTTP, but if it is required, then you know you have to use constexpr
instead.
C++23 reduces restriction about constexpr functions to allow to use functions which might be marked as constexpr
in future (standard), but there are nothing to declare variable as constexpr_if_possible.