4

I've found a weird issue on g++ 4.4 and 4.5. I've asked about this because i thought that i was making some silly error in the code. The original post is here but for post completitude i'll repost the problematic code in question here:

$ cat templatetemplate.cc
template <int i>
struct LabelTypeMap { typedef int type_t; };

template <bool>
struct Hold { typedef int type; };

template<typename Holder, template<typename Holder::type> class typeMap>
struct Whatever { };

template <bool Enable>
struct Now { typedef Whatever<Hold<ENABLE>, LabelTypeMap> concrete_t; };

Now<true>::concrete_t obj;

$ g++ -DENABLE=Enable -c templatetemplate.cc
templatetemplate.cc:11: error: type/value mismatch at argument 2 in template parameter list for ‘template<class Holder, template<typename Holder::type <anonymous> > class typeMap> struct Whatever’
templatetemplate.cc:11: error:   expected a template of type ↵
    ‘template<typename Holder::type <anonymous> > class typeMap’, got ↵
    ‘template<int i> struct LabelTypeMap’
marcelo@macbookpro-1:~/play$ 
$ g++ -DENABLE=true -c templatetemplate.cc
(no error)

It does not seem to be really a programmer error, althought it might be possible i'm missing some obscure rule of the template template parameter resolution. However i tried posting the bug to ubuntu tracker (hopefully they'll dismiss it or otherwise send the bug upstream)

So, just for the sake of checking if this is really a bug, i got myself a copy of the 2003 standard, and i have read section 14.3.3 a couple of times now, and still i feel i miss the slightest clue if passing a template template parameter with a parameter as in the sample code is allowed or disallowed. I'm not even sure this part of the document is mentioning anything about this

Here goes my question: do you know where this is specified?

EDIT: it is pretty interesting that this question has gone unanswered for over a week now: It leads me to believe that ISO c++ standard does not specify if we can use a previous template parameter to specify types of subsequent template parameters (at least in the stated form) and that is basically left for implementers to decide

2nd EDIT (10/01/2011): People, there is probably something about this that we are all missing (or else lots of highly skilled compiler designers are wrong): I tried this with intel c++ compiler XE 12.0 and i got this:

 $icpc ttemplatetemplate.cc -o ./x2test 
templatetemplate.cc(12): error: class template "LabelTypeMap" is not compatible with template template parameter "typeMap"
  struct Now { typedef Whatever<Hold<Enable>, LabelTypeMap> concrete_t; };
                                              ^


 compilation aborted for templatetemplate.cc (code 2)
$ icpc --version
icpc (ICC) 12.0.0 20101116
Copyright (C) 1985-2010 Intel Corporation.  All rights reserved.
Community
  • 1
  • 1
lurscher
  • 25,930
  • 29
  • 122
  • 185
  • I removed the link to the pirated C++ Standard. If ISO finds you linking to a pirate copy of it, I don't know what they will do with you. Better tell people to google for "ISO IEC 14882 2003 C++" to find it in the ISO catalogue and ... :) – Johannes Schaub - litb Jan 05 '11 at 05:12
  • BTW, Clang compiles this code fine. And I don't see the spec saying this is invalid (I don't see why it should be invalid either, but then I never tried writing a C++ compiler). So I take it that this is valid. – Johannes Schaub - litb Jan 05 '11 at 05:46
  • 1
    incredible, i didn't know you could 'pirate' the iso c++ standard. What is the point of a standard that is not publicly available? Preposterous! - yes i tried clang and it works for me too, so i conclude that this is just a g++ bug – lurscher Jan 05 '11 at 14:44
  • so i take that back, maybe is not a bug; what are the odds of g++ and intel compiler both agreeing to not accept this code, unless intel compiler team just follows to closely what g++ does? – lurscher Jan 12 '11 at 16:08
  • also comeau online agrees with them both, so for some reason, it seems the standard (either ISO or de facto) is that this code is wrong, even if we can't tell exactly why – lurscher Jan 13 '11 at 21:15

4 Answers4

1

I cannot find anything in the standard which forbids it, although I tried this simple code (which seems to me is a simplification of your problem) in Comeau :

template<int>
class A {};

template<class T, template<T> class U>
class B {};

B<int, A> b;

And it produces the following error :

"ComeauTest.c", line 4: error: a parameter of a template template parameter cannot depend on the type of another template parameter

I wish I could find which part of the standard actually forbids it...

icecrime
  • 74,451
  • 13
  • 99
  • 111
  • The syntax for a template template argument would be `, template class U>. The error that you then would get is roughly "Template A is not a valid argument for template template parameter U`. So, if U is not a template template paramenter, then what is it? – MSalters Dec 02 '10 at 12:58
  • @MSalters: sorry, I don't understand your comment :( I agree that `U` is a template template parameter, but what I understand from the OP problem is that he's trying to have a *non-type* template parameter depend on another template parameter (`T`). This is what I tried to reproduce in my simple example. – icecrime Dec 02 '10 at 13:11
  • your approach isn't working like this. `A` is a type, and can be a template type argument. `template A` is a template, and can be a template template argument. You're aiming for a mix. What you seem to want is to pass `int, A` and get `A`. You can do so, but not in one step: `template class UTempl> class B { typedef UTempl U; };` – MSalters Dec 02 '10 at 15:41
1

BTW, here's the solution I found to the underlying problem:

template <int i>
struct LabelTypeMap { typedef int type_t; };

template <bool>
struct Hold { typedef int type; };

template<typename Holder>
struct Whatever {
  typedef typename Holder::type HT;
  template <template <HT> class typeMap>
  struct Whatever2 { };
};

template <bool Enable>
struct Now { typedef typename Whatever<Hold<Enable> >::Whatever2<LabelTypeMap> concrete_t; };

Using a nested template, I can introduce a typename via a typedef.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 2
    You seem to be in the impression that `typename Holder::type` is not allowed as a template-parameter. But the Standard specifically disambiguates this: If a qualified name is used after `typename`, the use will introduce a non-type template-parameter. If an unqualified name follows `typename`, then it will introduce a type template-parameter. – Johannes Schaub - litb Jan 05 '11 at 05:43
0

I'm suspecting this weird construct: template<typename Holder::type> class typeMap What's that supposed to be? The typename Holder::type bit is weird; that's supposed to be a dummy name (identifier). Holder::type isn't even an identifier.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • in the instantiation Holder becomes type Hold or Hold, depending on the parameter to class Now. Hold::type and Hold::type are both a typedef for int. So the declaration for the template template parameter is saying that typeMap is a template that takes a integer constant as parameter – lurscher Dec 02 '10 at 13:35
  • Ah, right, that's the problem. You've got a spurious `typename`. You use `template class typeMap` when `typeMap` should be a template that takes an type. You use `template class typeMap` when `typeMap` should be a template that takes an integer (such as `LabelTypeMap`). Note the lack of `typename` in the latter case. – MSalters Dec 02 '10 at 15:47
  • So, basically, the problem you have is that `Holder::type` is a dependent name, and a type, but you can't use `typename` there because that's used for a template template paramater taking a type. To summarize (!): you want to pass a template template argument whose type argument is a dependent name depending on a previous template type argument (phew). – MSalters Dec 02 '10 at 16:12
-1

Isn't this how it is supposed to be?

This is because LabelTypeMap is itself a template (template template parameter) and hence requires a type to be specified.

template <bool Enable> 
struct Now { typedef Whatever<Hold<ENABLE>, LabelTypeMap<ENABLE> > concrete_t; };
Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • no, precisely because typeMap is a template template parameter it requires a template (i.e: LabelTypeMap) instead of a concrete type (i.e: LabelTypeMap). This is what you meant? – lurscher Dec 02 '10 at 13:42