42

If I define a struct template Bar which accepts a template argument:

template <template <int,bool,char> class>
struct Bar {};

I can instantiate it using a struct template such as Zod:

template <int,bool,char> struct Zod {};
Bar<Zod> a;

I can also instantiate it using a nested struct template such as JKL:

struct GHI {
  template <int,bool,char>
  struct JKL {};
};
Bar <GHI::JKL> b;

Why can't I instantiate Bar using a nested variadic struct template such as DEF?:

template <typename ...Ts>
struct ABC {
  template <Ts ...>
  struct DEF {};
};

Bar<ABC<int,bool,char>::DEF> c;

G++ 4.9.2 complains of a type/value mismatch; while Clang 3.4.2's error reports that the template template argument has different template parameters than its corresponding template template parameter.

user2023370
  • 10,488
  • 6
  • 50
  • 83
  • 1
    Doesn't compile on gcc 5.1.0 or clang 3.6.0 either, for what it's worth. – Barry May 17 '15 at 23:17
  • I am not able to instantiate the inner template either, `ABC::DEF foo;` doesn't work, `error: missing template arguments before foo` – vsoftco May 17 '15 at 23:22
  • @vsoftco [An explicit instantiation of the outer template compiles](http://rextester.com/QTDET12337). Moreover, [it works if you change the parameter pack to three separate template arguments](http://rextester.com/WIZ86669). – David G May 17 '15 at 23:27
  • 2
    @vsoftco `ABC::DEF<4,true,'c'> foo;` works. – Barry May 17 '15 at 23:30
  • @Barry sorry, I misused the template, using types instead of values on the inner template. Yes, works on my side too. – vsoftco May 17 '15 at 23:31
  • 1
    The tricky part is that `DEF` actually takes a non-type template parameter pack. See the example in [temp.param]/p15. – T.C. May 18 '15 at 00:09
  • @T.C. Is there a reason you couldn't use `value_holder::apply` in that example as a template template parameter? – Barry May 20 '15 at 10:50
  • The small example mentioned is from paragraph 15 (p15) of Section 14.1 (Template parameters) from the C++11 (or C++14) standard. `ABC::DEF` is essentially the same as `value_holder::apply`. I think @T.C.'s point was merely to highlight that the nested `DEF` struct template is parameterised using non-types. – user2023370 May 20 '15 at 14:23
  • 1
    @Barry My point is that `DEF`'s technically parameterized over a non-type parameter pack. And a template template argument taking a pack doesn't match a template template parameter not taking packs. – T.C. May 20 '15 at 15:27
  • @T.C. Ah yes, I think you have it. Non-type parameters are, shall we say, more strongly typed; the same issue with type parameters will seem more obvious: `template – user2023370 May 20 '15 at 19:46
  • @T.C.: I have troubles understanding your point. Upon instantiation of `ABC`, `DEF` should be just a regular class template taking three non-type parameters. The fact that its parameter list is a pack expansion should not be relevant, as the template is used after that pack is expanded. Or were you just trying to figure out what might have confused the compiler? This looks like a bug to me. – Andy Prowl May 25 '15 at 22:57
  • @AndyProwl The (sole) parameter of `ABC<…>::DEF` is always a pack. – Columbo May 25 '15 at 23:47
  • @Columbo: Yeah, but it is also a pack expansion, and as such it expands to a list of exactly 3 types when instantiated as in the OP's example - § 14.5.3/7. – Andy Prowl May 26 '15 at 00:13
  • 2
    @AndyProwl That's irrelevant. It is still a parameter pack, which is why §14.3.3/3 does not allow for a match. – Columbo May 26 '15 at 00:31
  • @Columbo: I don't understand. Why do you assume 14.3.3/3 should be interpreted as if the pack was unexpanded? The pack expansion makes `Ts...` be a list of exactly three types, which means the nested `DEF` template has exactly 3 non-type parameters. Those are the ones that, according to 14.3.3/3, must be matched against the parameter list of `Bar`'s template template argument. – Andy Prowl May 26 '15 at 08:13
  • @AndyProwl No, it has one template parameter, that is a pack. – Columbo May 26 '15 at 08:28
  • @Columbo: This does not answer my question ("Why?"). Yes it is a pack and it is also a pack expansion. What leads you to the conclusion that the pack should be treated as unexpanded when considering the rules in 14.3.3/3? (let's take it to the chat to avoid polluting this thread) – Andy Prowl May 26 '15 at 08:51
  • @AndyProwl I haven't responded to your question. I corrected you on the fact that there is exactly one parameter. The misunderstanding you have is that the pack expansion suddenly creates three template parameters, which is not the case. There is one parameter pack that can match three non-type template arguments of appropriate types, not more. – Columbo May 26 '15 at 09:07
  • @Columbo: But how do you deduce that it is not the case? § 14.5.3/7 seems to imply it is: "The instantiation of a pack expansion [...] produces a list E1, E2, ..., EN. Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. Such an element, in the context of the instantiation, is interpreted as follows: *if the pack is a template parameter pack, the element is a template parameter (14.1) of the corresponding kind (type or non-type)* designating the type or value from the template argument; [...]" – Andy Prowl May 26 '15 at 09:24
  • @AndyProwl Different things, but e.g. you can pass no parameters to `ABC` at all, and the instantiated template parameter list of `DEF` is still valid. This is covered by 14.5.3/7 as well, but it would not be possible if things would work as you describe, because a template without any parameters is flat out ill-formed. My answer is that the (inner) parameter pack cannot match any arguments, but is one (valid) template parameter. It can be [instantiated without arguments](http://coliru.stacked-crooked.com/a/9fbee6bfdf2dacad) though. – Columbo May 26 '15 at 10:04
  • I don't know why, but aliasing helps! template using alias = ABC::DEF; Bar c; My gcc version is 5.1 – ivaigult May 26 '15 at 17:00
  • @AndyProwl What Columbo said. Call it `template struct DEF { };`; it's a pack expansion of `Ts`, but `Values` is a pack in its own right. Sure, it's a weird kind of pack compared to "normal" packs, but under the current rules it's still a pack, so the rules for packs apply. It's arguably a defect, but that's what the standard says, and what the current compilers have implemented. – T.C. May 26 '15 at 21:02

2 Answers2

5

Let's give DEF's parameter pack a name for ease of reference:

template <typename ...Ts>
struct ABC {
  template <Ts ... Values>
  struct DEF {};
};

The key point here is that by [temp.param]/p15, Ts... Values is both a pack expansion of Ts and a declaration of a parameter pack Values.

If a template-parameter is [...] a parameter-declaration that declares a parameter pack (8.3.5), then the template-parameter is a template parameter pack (14.5.3). A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded parameter packs is a pack expansion.

Since DEF takes a non-type parameter pack, it doesn't match a template template parameter that doesn't take packs ([temp.arg.template]/p3):

A template-argument matches a template template-parameter P when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias template A matches the corresponding template parameter in the template-parameter-list of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively. When P’s template-parameter-list contains a template parameter pack (14.5.3), the template parameter pack will match zero or more template parameters or template parameter packs in the template-parameter-list of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).

To be sure, Values is rather weird for packs - for every specialization of ABC, Values must contain a fixed number of arguments - but under the current rules it's still a pack, so the rules for packs apply.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    I think I understand your interpretation, but there are still unclear points to me. In particular, which "rules for packs" are you referring to? Notice, that the last part of the paragraph you quote refers to the inverse situation (i.e. when the *parameter*, rather than the argument, is a pack). The first part of the quote mentions that a template template-argument matches a template template-parameter if the corresponding template parameters match, and that these can be of three kinds: "type", "non-type", and "template". I don't see special rules for "packs", nor is "pack" a kind of parameter – Andy Prowl May 26 '15 at 21:58
  • @AndyProwl Right. The second half says that if there's a pack in the parameter, it can match packs and non-packs in the argument. By default, if the parameter is not a pack, then it cannot match a pack in the argument, because nothing says a (non-pack) template parameter in the parameter can match a parameter pack in the argument. – T.C. May 26 '15 at 23:35
  • 1
    With `template – tmlen May 27 '15 at 14:52
3

Like Barry said before about:

ABC<int,bool,char>::DEF<4,true,'c'> foo

And make a try and worked on Coliru online compiler gcc 5.1 c++14 in this site Compiler:

#include <iostream>
 template <template <int,bool,char> class>
struct Bar {};
template <int,bool,char> struct Zod {};

Bar<Zod> a;

struct GHI {
  template <int,bool,char>
  struct JKL {};
};

Bar <GHI::JKL> b;

template <template <typename... Ts> class>
struct Base {};
template<typename... Ts>
struct Floor {};
Base<Floor> c;

template <typename... Ts>
struct ABC {
  template <Ts... val>
  struct DEF {};
};
ABC<int,bool,char>::DEF<4,true,'c'> foo;

I made a search and found this Template parameter list.

Pack expansion may appear in a template parameter list:

 template<typename... T> struct value_holder
{
    template<T... Values> // expands to a non-type template parameter 
    struct apply { };     // list, such as <int, char, int(&)[5]>
};

where i tested some stuff in the run code compiler at: http://en.cppreference.com/w/cpp/language/parameter_pack but also i found this Ellipses and Variadic Templates in visual studio 2013: https://msdn.microsoft.com/en-us/library/dn439779.aspx