Deduce one of two template parameters with parameter pack in C++20

Viewed 29

I have an N-dimensional array class with two template parameters, a class and a size_t. To construct a 3-dimensional array of size x by y by z, I would like to be able to use:

ArrayND<float> A(x, y, z);

...but can't figure out how to do so--as it stands, I have to redundantly specify the dimension:

ArrayND<float, 3> A(x, y, z);

I thought that this deduction guide:

template <class T, class ...I>
ArrayND(I...) -> ArrayND<T, sizeof...(I)>;

...would be sufficient to allow the omission of the dimension parameter, but it isn't--when I try to compile a program containing "ArrayND<float> A(x, y, z)" with G++ 12.1.0 using -std=c++20, it fails ("error: wrong number of template arguments (1, should be 2)"). Is it possible to do what I'm trying to? If so, what am I doing wrong?

A simplified version of the class in question:

template <class T, size_t N>
class ArrayND {
    // Members: the actual storage, and the conceptual size
    std::vector<T> storage;
    size_t dims[N];

public:
    // Constructor: ArrayND<T, N>(dim1, dim2, ...);
    template <class ...I> requires (sizeof...(I) == N && std::is_integral_v<std::common_type_t<I...>>)
    constexpr ArrayND(const I ...i): storage((i * ...)), dims{i...} {}

private:
    // Indexing helper--convert from (i, j, k...) to the actual index within storage
    template <decltype(N) M=N-1, class I, class ...J>
    constexpr const auto flattened_index(const I i, const J ...j) const {
        auto index = i * std::accumulate(dims+N-M, dims+N, 1, std::multiplies());
        if constexpr (sizeof...(J) > 0) index += flattened_index<M-1>(j...);
        return index;
    }

public:
    // Index a cell
    template <class ...I> requires (sizeof...(I) == N && std::is_integral_v<std::common_type_t<I...>>)
    constexpr auto &operator()(const I ...i) { return storage[flattened_index(i...)]; }

    // Access underlying data
    constexpr auto data() { return storage.data(); }
};

A minimal working example can be found here; delete the 3 on line 47 to see the failure.

0 Answers
Related