I've been messing around with an SVN build of clang to experiment with the relaxed rules for constexpr
. One of the things I've been unable to determine as of yet is whether it's possible to loop through the elements inside a tuple at compile-time in a constexpr function.
Because I don't have a C++14 compliant standard library to test on, I've prepared the following equivalent test:
template<int N>
constexpr int foo() {
return N;
}
constexpr int getSum() {
auto sum = 0;
for (auto i = 0; i < 10; ++i) {
sum += foo<i>();
}
return sum;
}
constexpr auto sum = getSum();
The interesting part here is foo<i>()
. In a non-constexpr function I would expect this to fail to compile, because you simply cannot use a runtime int to generate a compile-time instantiation of a template. Because this is a constexpr
function, however, I question whether this would be possible. In particular, the value is known at compile-time, even if it is allowed to mutate.
I know that the following code will compile:
constexpr auto nValue = 2;
foo<nValue>();
In SVN clang, my first example does not:
test2.cpp:19:12: error: no matching function for call to 'foo' sum += foo(); ^~~~~~ test2.cpp:11:15: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'N' constexpr int foo() { ^
For starters, I struggle to interpret the second part of this error message. That aside, is it mandated by the C++14 standard, and if so, does anyone know why this syntax wouldn't be allowed (simple oversight or to protect against something)?
A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.
Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.
constexpr int a = 2; Static specifies the lifetime of the variable. A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.
For example, constexpr variables and instances of user-defined types are automatically thread-safe and can be stored in ROM; constexpr functions that are evaluated at compile-time, are done with their work at run time.
That aside, is it mandated by the C++14 standard, and if so, does anyone know why this syntax wouldn't be allowed (simple oversight or to protect against something)?
That's because constexpr
is not exclusive to compile-time computations or usage. A constexpr
function is just that, allowing a function (or variable) to be used in a constant expression. Outside of that, they're regular functions. A constant expression just so happens to be required in certain contexts such as static_assert
or array sizes, etc that are compile-time only situations.
You'll notice in your code that you loop through a variable but the variable you're looping through itself isn't constexpr
so it isn't a constant expression to be used in that template instantiation of N
. As it stands, it's no different than doing this in C++11:
constexpr bool f(int x) {
static_assert(x > 10, "..."); // invalid
return true;
}
Which is obviously invalid because as I mentioned earlier, you don't have to use constexpr
functions in exclusive compile-time situations. For example, nothing is stopping you from doing this:
constexpr int times_ten(int x) {
return x * 10;
}
int main() {
int a = times_ten(20); // notice, not constexpr
static_assert(times_ten(20) == 200, "...");
static_assert(a == 200, "..."); // doesn't compile
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With