Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template size_t deduction from constructor's arguments

Tags:

c++

I'm trying to figure out how to make the compiler deduce template parameters based on arguments passed to the constructor. Here's what I tried:

#include <array>

template<size_t N, size_t M>
class A {
public:
    A(const std::array<float, N>& n, const std::array<double, M>& m)
        : nElements(n), mElements(m) {
    }

private:
    std::array<float, N>  nElements;
    std::array<double, M> mElements;
};

int main() {
    A<2, 3> a({1.4f, 2.5f}, {3.0, 2.1, 4.8});
    // ^
    // |
    // how can i avoid <2,3> expclicit declaration here?
}

Thank you very much for any possible help!

like image 328
vilu Avatar asked Jan 25 '23 05:01

vilu


2 Answers

As @Thomas's answer says, you can't deduce the class template arguments from the constructor arguments till c++17.

But providing a deduction guide won't work in this case, as pointed out in the comments, since the template arguments of std::array can't be deduced from a brace-init-list.

We can sidestep this issue by creating a deduction guide where the arguments are raw arrays. This solves the problem since the size of raw arrays can be deduced from brace-init-lists.

// deduce the size using raw arrays
template<size_t N, size_t M>
A(float const (&)[N], double const (&)[M]) -> A<N,M>;

int main() {
   A a({1.4f, 2.5f}, {3.0, 2.1, 4.8}); // yay
}
like image 188
cigien Avatar answered Jan 27 '23 18:01

cigien


C++ doesn't deduct the arguments of the class template from arguments passed to the class's constructor, until C++17.

In versions before C++17, the customary workaround is to create a factory function:

template<size_t N, size_t M>
A<N, M> make_A(const std::array<float, N>& n, const std::array<double, M>& m) {
    return A<N, M>(n, m);
}

You see examples of these in the standard library as well, such as std::make_pair and std::make_shared.

like image 22
Thomas Avatar answered Jan 27 '23 20:01

Thomas