1
votes

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";
    });
}
1
It's not really a "bug" when Microsoft's own conformance docs state that they haven't implemented that feature yet. It is simply "to be done". Bugs are for when you claim to support something but don't do it correctly. - Nicol Bolas
Do you know which PR corresponds to this feature? - cos
What is a "PR"? - Nicol Bolas
The document number. Or the entry in the table mentioned above, so I could track the feature. - cos

1 Answers

1
votes

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.