Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template argument deduction trick for constructor with parameters depending on integer template

Tags:

c++

templates

I have found a code in https://stackoverflow.com/a/36132696/3206356 and I try it. It works, but I don't fully understand what happens there.

I have duplicated code from that link below:

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)
    {
        ...
    }
};

For example, we try to use it next way:

Vector<3> a(1.0, 2.0, 3.0);

How type deduction works here?

p.s. As I understand when the compiler sees that line, first of all, it tries to deduce types for specialization. It deduces N as 3 and Is as empty sequence and then fails when can't find appropriate constructor. General template is not defined, so compilers must fail here too. But what happens next?

like image 607
akulinich Avatar asked Jun 26 '26 20:06

akulinich


1 Answers

This part declares (not defines) the default specialisation of the template class Vector. The second template argument defaults to an index sequence of 0...N-1

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

The default argument is important as it serves to present a simple interface and hide the complexities of the next specialisation...

This specialisation is the one instanciated as a result of the above default declaration. The purpose of the index sequence is to carry the variadic sequence of Is (i.e. 0 ... N-1).

template <size_t N, size_t... Is>
class Vector<N, std::index_sequence<Is...>> 
{

Defines sufficient storage

private:
    std::array<double, N> vals;

Provides a means of translating on of the sequence Is from a size_t into a type (in this case, double)

    template <size_t >
    using double_ = double;

public:

Defines the constructor to take double_<0>, double_<1> ... double_<N-1>. But double<N> for any N is a typedef of double. So what this line is doing is providing a constructor which takes one double for each Is. i.e. exactly as many doubles as required to build the array. It's pretty clever actually.

    Vector(double_<Is>... vals)
    {
        ...
    }
};
like image 103
Richard Hodges Avatar answered Jun 29 '26 11:06

Richard Hodges



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!