5

I come across with a weird problem in which MSVC doesn't let me to use fold expression to initialize an array in the following:

#include <iostream>

template <typename T, std::size_t ...dims>
class Matrix {
public:
    void print()
    {
        std::cout << (... + dims) << '\n';
    }
    
    T matrix[(... + dims)];      // <-- error C2059: syntax error: '...'
};

int main()
{
    Matrix<int, 3, 3, 3> m;
    m.print();
    Matrix<int, 3, 2, 1> n;
    n.print();
    return 0;
}

Here is the errors:

(10): error C2059: syntax error: '...' (11): note: see reference to class template instantiation 'Matrix' being compiled (10): error C2238: unexpected token(s) preceding ';'

I tried GCC and everything just worked perfectly fine!

Is there any workaround to use fold expression directly to initialize an array with MSVC?

Thank you so much guys!

Dai
  • 141,631
  • 28
  • 261
  • 374
Nima Ghorab
  • 309
  • 1
  • 3
  • 13
  • 1
    Works [here](https://wandbox.org/permlink/xjOhQ7isOncjPSSg) with GCC and C++17. – Jason Dec 16 '21 at 09:12
  • 2
    I retracted my comment. I didn't realise the error was on the _third_ use of `...` - if it really was an issue of the compiler not recognizing the syntax it would have complained about the 2 preceding instances lines first. I tried it on godbolt with VC19.30 with `/std:c++20` and the error reproduces there too. – Dai Dec 16 '21 at 09:17
  • @Evg This one works but I prefer not to use dummy variable while I can use fold expression directly! – Nima Ghorab Dec 16 '21 at 09:20
  • 3
    @NimaGhorab Then you may need to change compiler. It looks like a bug in MSVC. Both `g++` and `clang++` compiles it fine. Have you tried it in VS2022 beta? – Ted Lyngmo Dec 16 '21 at 09:21
  • 1
    @TedLyngmo Yes I tried it with the latest version of MSVC but errors are still there. – Nima Ghorab Dec 16 '21 at 09:25

1 Answers1

5

This looks like a bug in the MS compiler. As with any bug of such kind, it's hard to tell what exactly goes wrong unless you know MS compiler internals.

A workaround is the introduction of an intermediate member variable:

template<typename T, std::size_t... dims>
class Matrix {
    // ...
    static constexpr std::size_t my_size = (... + dims);
    T matrix[my_size];
};

or a static member function:

    static constexpr std::size_t my_size() { return (... + dims); }
    T matrix[my_size()];
Evg
  • 25,259
  • 5
  • 41
  • 83
  • 2
    Not to mention that doing so we can reuse the same `my_size()` in `print`, easily test it somehow and if, later, we decide that a `*` would be more appropriate than a `+`, change it in just one place. – Bob__ Dec 16 '21 at 10:00
  • @Bob__ Good point, too. Thanks. – Evg Dec 16 '21 at 10:42
  • 1
    @Evg Thank you for the answer I submit this in Developer Community of Microsoft. I hope they fix this bug as soon as possible! – Nima Ghorab Dec 16 '21 at 11:50