简体   繁体   中英

Non-type template parameters in function and in inheritance

I'm following this great tutorial. The author heavily uses variadic templates and I came to a point where I'm stuck, can't understand. Can you help me?

1. Why isn't this compiling?

// this is simple
template<size_t I, typename T>
struct tuple_element
{
    T value;
};

// this does NOT compiles: error: parameter pack 'Indices' must be at the end of the template parameter list
template <size_t... Indices, typename... Types>
struct tuple_impl : tuple_element<Indices, Types>...
{
};

Next, the author have this code that compiles fine:

template <size_t... Indices>
struct index_sequence
{
    using type = index_sequence<Indices...>;
};

template <typename Sequence, typename... Types>
struct tuple_impl;

template <size_t... Indices, typename... Types>
struct tuple_impl<index_sequence<Indices...>, Types...>
  : tuple_element<Indices, Types>...
{
};

2. Why in this case everything ok? I see almost the same pattern here: tuple_element<Indices, Types>...

3. Why this can't be compiled:

template <size_t... Indices>
void g(Indices...){}; //error: variable or field 'g' declared void 

The error you are seeing is in the passing of parameters. This is a compile error:

template <size_t... Indices, typename... Types>
struct tuple_impl
{};

live example

The rule is you cannot have one pack followed by another in a template class template parameter list.

The second example is a specialization, where the pack rule does not exist. The template parameters of a specialization are merely the types and values which are extracted from the pattern matching against the primary templates, as guided by the <> portion of the specialization after the type name.

As they are never passed in in that same list & order, having one ... after another doesn't cause any ambiguity. With a primary template, the order matters, and anything after a ... is difficult to distinguish from more of the ... . Probably to keep the compiler's job easier, even in cases where it cannot be ambiguous (say, a pack of literals followed by a pack of types), C++ bans its use.

  1. The compiler would have no means to distinguish when the first sequence ends and the second starts - therefore it is allowed to have only one parameter pack in variadic templates, at the end.

     tuple_impl<a, b, c, d, e, f> //is d still an index or already a type? what about e? 
  2. This works, because tuple_impl itself is a template that has itself only one parameter pack, the Types... . It just happes that in this specialization the first parameter is a template, too, which has a parameter pack, too. So, in contrast to one template with two packs, you have two templates with one pack each, which is ok.

  3. This does not have to do with variadic templates, ie it would not work with a single argument either, for the same reason. The fact is, that since Indices... are not types but values, you are not defining a function. If it was not void, the compiler would have had problems later. Consider this example, which is slightly modified but essentially a similar construct:

     template <size_t I> unsigned g(I) {} 

The middle line is central: The compiler thinks that it is a variable definition, initialized with I . Therefore the error in your case, because variables of type void simply don't make sense. My compiler then emits a warning about the template, it thinks that g is a templated variable, and those are a C++1y extension. After that is done, he realizes the variable definition is not finished by a ; , emits an error and exits...

Just to add some important thing: this is a test snippet:

int main( int argc, char** argv )
{
    using i3 = index_sequence<1, 2, 3>;
    tuple_impl<i3, int, double, char> tup;

    return 0;
}

Note: here you pass this i3 as the "index pack". The "master template" always defines how the parameters have to be passed to the template. The template<...> statement if set for specialization does not define anything, but just what internally the parameter combination may spread inside the specialization, but it's not a part of public interface.

For example, if you try to use <1, 2, 3, int, double, char> as a parameter specification (which would theoretically match the template parameter specification for the specialization), it will fail to compile.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM