3

Possible Duplicate:
Using template parameters as template parameters

Here's a code snippet of some heavily templated container classes used to bind an arbitrary amount of fields of arbitrary types. A co-worker of mine found that my code didn't compile under GCC and after much research he found the fix to get it to deduce the templates correctly by adding ::template ... Neither of us had ever seen this before and still don't really know what this is other than something that GCC needs for my code that Visual Studio 2010 does not need.

    template< typename T, int N >
    struct SingleBindMemberStruct
    {
        typedef typename TGenericBindingHandler<T>::BindToUse BindType;
        BindType m_Member;

        template< typename ContainerClass >
        static void AddBinding(CPackedTableDataSpec* spec)
        {
// Perhaps with newer versions of the compilers we can find a syntax that both accept. This is with gcc-4.5 and Visual Studio 2010
#if defined(__GNUC__)
            TGenericBindingHandler<T>::template AddBinding<ContainerClass>(spec, N, &ContainerClass::template SingleBindMemberStruct<T,N>::m_Member);
#else
            TGenericBindingHandler<T>::template AddBinding<ContainerClass>(spec, N, &ContainerClass::SingleBindMemberStruct<T,N>::m_Member);
#endif
        }
    };

Does anyone know syntactically what ::template can or should be used for? If anyone has a snippet from the standard that describes it that would be perfect!

Edit:

Alright so sounds like it is really as simple as helping the compiler determine what is a template and since this is a static function we use the scope resolution operator rather than the dot operator to tell the compiler of the template. So now the only remaining question is why does Visual Studio not need this as well?

Community
  • 1
  • 1
AJG85
  • 15,849
  • 13
  • 42
  • 50
  • 2
    It doesn't "just make it compile". It disambiguates. You can write code that compiles whether or not you have "::template", and will have different results. – Johannes Schaub - litb May 13 '11 at 17:40
  • I'm not convinced that this is an exact duplicate of the question above - personally I'd vote to reopen if I had 3000+ rep :) Partly because I suspect Johannes might have a better answer to this question than has already been given... – Stuart Golodetz May 13 '11 at 17:44
  • Essentially the linked question answers the reason it is needed so it that is half my question. The other half is simply curiosity of why Visual Studio doesn't need it and what the standard says about compiler interpretations of template parsing to make both compilers correct (or incorrect). – AJG85 May 13 '11 at 18:01

2 Answers2

2

It tells the compiler that AddBinding is a template -- since the definition of AddBinding is dependent on T, the compiler wouldn't otherwise know this at the right stage of the compilation process (I'm no expert on the details, but it's to do with the C++ compilation model AFAIK). By writing template after the ::, you give the compiler information it otherwise wouldn't have. I guess more specifically, it knows that it's dealing with a template and not a < operator when it sees < after AddBinding.

If you want a more detailed answer, you might want to check out C++ Templates: The Complete Guide. (I think it's available as a PDF if you search Google.)

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
  • Actually, I think it tells the compiler that `ContainerClass` is a template parameter, since both branches of the `#if` use it on `AddBinding`. See this: http://stackoverflow.com/questions/642229/why-do-i-need-to-use-typedef-typename-in-g-but-not-vs – Chris Morgan May 13 '11 at 17:27
  • @Chris: Surely the same thing in this case? If `AddBinding` (i.e. the template nested in `TGenericBindingHandler`) is a template, then `ContainerClass` is evidently the corresponding template parameter. Or is there a subtle distinction I'm missing? – Stuart Golodetz May 13 '11 at 17:32
  • @Stuart I agree that the standard requires the `::template` to be on both `AddBinding` and `ContainerClass`. However, looking purely at the code, the difference only exists in the 3rd argument to `AddBinding`. – Chris Morgan May 13 '11 at 17:37
  • AddBinding is a static template function with a template return type and uses this templated object's template to define a parameter. Sounds horrible but works great sort of like a `std::tuple` with aliasing. Now if only I had support for variadic templates I wouldn't need so many typedefs and defaulted template args. – AJG85 May 13 '11 at 17:37
  • @Chris: I missed that there was another `::template` further to the right in the code (it's off the screen for me because the line isn't wrapped). – Stuart Golodetz May 13 '11 at 17:39
  • In this case, the `::template` to the right tells the compiler that `SingleBindMemberStruct` is a template -- which it can't otherwise assume without seeing the definition of `ContainerClass`. – Stuart Golodetz May 13 '11 at 17:41
  • It's actually telling it that `typename ContainerClass` is a template in the scope of the function, it would know that `SingleBindMemberStruct` is a template because this is all within the definition of `SingleBindMemberStruct` so it has already parsed the line `template ` for that object. – AJG85 May 13 '11 at 17:50
  • @AJG85: At what point does it know that the `SingleBindMemberStruct` in `ContainerClass` is the same `SingleBindMemberStruct` containing the `AddBinding` static template function? – Stuart Golodetz May 13 '11 at 17:58
  • @AJG85: I guess what I'm trying to say is -- presumably it can't know that `ContainerClass::SingleBindMemberStruct` is a template just because it's already seen a (possibly completely unrelated) `SingleBindMemberStruct` which is. It only knows at the point at which it knows which `ContainerClass` is being talked about. – Stuart Golodetz May 13 '11 at 18:00
  • Well it should because it is using the same template args. If I had made a `typedef SingleBindMemberStruct ThisType;` above it would make it more readable, I might go do that right now actually. – AJG85 May 13 '11 at 18:08
1

AddBinding is a dependent name, it isn't recognized as template during compilation. Without template it will be interpreted as function pointer and < comparison, which doesn't make sense at all.

Gunther Piez
  • 29,760
  • 6
  • 71
  • 103