Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable number of constructor parameters depending on integer template

I'm writing a container storage class template that wraps a private std::array in order to add some functionality to it. The template parametrises the number of values, as follows:

template<size_t N> class Vector {
private:
    array<double, N> vals;
public:
    [...]
};

I'd like the constructor for the class to only accept N doubles to fill the array, but I can't find a good way to do this. Variadic arguments don't provide a mechanism to check how many of them there are, so they're right out. Parameter packs don't do floating-point promotion, but I'd be willing to deal with that if I could only figure out how to use them for this.

I've tried following the approach in the answer to Member function template with the number of parameters depending on an integral template parameter but I can't understand the significance enable_if<>::type=0 section. I've tried naïvely copying that code in (though I'd much rather understand how it works. I've seen people use ::value in other places but I can't find any documentation on why) but expanding the resulting parameter pack doesn't seem to work. My other concern with parameter packs is that I'm not sure that they'd ensure the types of all arguments were the same.

I've tried running a static_assert on the size of an initializer list, in the body of the constructor, but of course the size of the list is not constant at compile time, so that doesn't work either.

Is there a standard approach here? Am I just using parameter packs wrong?


Update: I've got the approach in the answer I linked above partly working:
template<size_t N> class Vector {
private:
    array<double, N> vals;
public:
    template <typename ...T,
          typename enable_if<sizeof...(T) == N, int>::type = 0>
    Vector(T ...args) {
        vals = {args...};
    }
};

The issue is now that the enable_if term in the template means that when I initialise a Vector with, for example,

Vector<3> V {1.0, 2.0, 3.0};

It requests a template specialisation Vector<3>::Vector<double, double, double, 0> rather than <double, double, double>. How do I get rid of this stray term in the template?

like image 632
TroyHurts Avatar asked Mar 21 '16 13:03

TroyHurts


People also ask

How many constructor arguments is too many?

In the Java edition of Building Maintainable Software, Joost Visser advises keeping the number of parameters to no more than four.

What is template parameter in c++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

Don't get what you mean by this:

Variadic arguments don't provide a mechanism to check how many of them there are, so they're right out

template <typename ...T>
Vector(T... args) {
    static_assert(sizeof...(args) <= N, "oops");
}

Should work..

like image 141
Nim Avatar answered Sep 21 '22 04:09

Nim


You could additionally generate a pack of the right size via some template specialization tricks:

template <size_t N, class = std::make_index_sequence<N>>
class Vector;

template <size_t N, size_t... Is>
class Vector<N, std::index_sequence<Is...>> 
{
private:
    std::array<double, N> vals;

    template <size_t >
    using double_ = double;
public:
    Vector(double_<Is>... vals)
    {
        ...
    }
};

That is a non-template constructor which takes N doubles.

like image 28
Barry Avatar answered Sep 19 '22 04:09

Barry