Reputation: 958
I'm trying to pass a static constexpr std::array
as a non-type template parameter. However accessing an array element gives a non compile-time constant value on msvc compiler.
MSVC (16.4.5, 16.5) fails to compile the sample, but clang (9, 10) and gcc (9.1, 9.2, 9.3) compile fine.
What is the correct behaviour according to the current standards (>=c++20)? Is this a MSVC compiler bug?
Here is the sample https://godbolt.org/z/7YsnAF
#include <array>
#include <iostream>
template <typename T, size_t N, const std::array<T, N> & arr, typename Fn, size_t Index = 0>
void iterate_static_array(Fn && fn) {
static constexpr T e = arr[Index];
fn.template operator()<e>();
if constexpr (Index + 1 < N) {
iterate_static_array<T, N, arr, Fn, Index + 1>(std::forward<Fn>(fn));
}
}
int main() {
static constexpr std::array<int, 10> values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
iterate_static_array<int, 10, values>([]<int e>() {
std::cout << "compile-time e = " << e << "\n";
});
}
Upvotes: 1
Views: 427
Reputation: 22152
I would say it is a bug.
The only C++20 feature you are using is the template syntax for lambdas, which according to Microsoft's documentation should already be supported since VS 2019 16.2.
If you remove that and test e.g. the following program:
#include <array>
#include <iostream>
template <typename T, size_t N, const std::array<T, N> & arr, typename Fn, size_t Index = 0>
void iterate_static_array(Fn && fn) {
static constexpr T e = arr[Index];
fn.operator()();
if constexpr (Index + 1 < N) {
iterate_static_array<T, N, arr, Fn, Index + 1>(std::forward<Fn>(fn));
}
}
int main() {
static constexpr std::array<int, 10> values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
iterate_static_array<int, 10, values>([]() {
});
}
then there is no C++20 feature left and since C++17 this should compile, because you are allowed to pass a reference to an object with static storage duration as template argument and its usage as arr[Index]
is also a constant expression, as the reference was initialized with a constant expression and the referenced object is also constant initialized.
Yet MSVC still gives the same error message, whether in c++2a or c++17 mode. Both GCC and Clang compile this in C++17 mode.
Upvotes: 2