3

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?

akulinich
  • 85
  • 1
  • 5
  • No, it deduces N as 3 and then the second argument as `std::make_index_sequence<3>`, because that's what the default template parameter says. `Is...` can never be an empty sequence (unless `N` is `0`). – n. m. could be an AI Jun 18 '17 at 10:22
  • But `N` from the general template and `N` from specialization are different. When I wrote that `N` is deduced as `3`, I meant for specialization. And as I understand when we deduce types for specialization we know nothing about `std::make_index_sequence`. Am I wrong? – akulinich Jun 18 '17 at 10:58
  • 2
    It works like this. The compiler sees `Vector<3>`. It goes to the *main template*, deduces the parameters it can, and fills arguments that have default values. This turns `Vector<3>` into `Vector<3, std::make_index_sequence<3>>`. *Then* a suitable specialisation is found for this instantiation and the parameters are deduced again. – n. m. could be an AI Jun 18 '17 at 10:59
  • I got it now! Thanks! =) – akulinich Jun 18 '17 at 11:10

1 Answers1

1

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)
    {
        ...
    }
};
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142