0
votes

There is a template class A used in class hierarchy of B::C_# which specialize method create() of A:

template <typename T>
class A
  : public std::map<std::string, double (T::*)() const>
{
  ...

  void create();

  ...
};

template <typename T>
void A<T>::create()
{ assert(false); }

One of these subclasses C_# (let's say C_0) was great until recently. Everything went fine until C_0 decided to become a template. He got everything going except this create() specialization. It tries to specialize create() the following way:

template<class N1, class N2>
class C_0: public B<N1, N2>
{
  ...
}

...

template<class N1, class N2>
some_namespace::A< some_namespace::C_0<N1, N2> >
  some_namespace::C_0<N1, N2>::A_;

template <>
void some_namespace::A< C_0<N1, N2> >::create() // line 1151
{
  blah_(&C_0<N1, N2>::get_stuff);
}

but C_0's attempts so far failed:

C_0.h:1151:45: error: 'N1' was not declared in this scope
C_0.h:1151:49: error: 'N2' was not declared in this scope
C_0.h:1151:51: error: template argument 1 is invalid
C_0.h:1151:51: error: template argument 2 is invalid
C_0.h:1151:53: error: template argument 1 is invalid
C_0.h:1151:63: error: 'create' is not a template function

Please help poor creature to overcome his trouble.

Also tried to do template method specialization in specialized C_0:

namespace some_namespace
{
  class C_0_specialized: public C_0<double_t, size_t>
  {};

  template <>
  void A<C_0_specialized>::create()
  {
    blah_(&C_0_specialized::get_stuff);
  }
}

This time it compiles, but calls the original method, which is void A<T>::create() { assert(false); }

Solution

Ok, so I ended up doing partial specialization of the whole template class A within C_0 template level with C_0 argument list:

template<class N1, class N2>
class A< C_0<N1, N2> >
{

  ...

  void create()
  {
    blah_(&C_0<N1, N2>::get_stuff);
  }

  ...

}

The reason is because: 1) partial specialization of template methods is not allowed, so it is not possible to specialize just void create() and when class is partially specialized all methods and variables have to be re-defined in the specialization; 2) explicit specialization of template method void create() is not possible within C_0 level because A depends on C_0 template argument list; 3) Moving void create() specialization to C_0_specialized, where it could be explicitly specialized because at C_0_specialized the template argument list is resolved, was not possible because the instance of A (instantiated as A_ in the code above) is used within template C_0 and therefore A_ would not see the specialization of A at C_0 level. That's why at that level it was calling the base version of void create(). Also moving A_ to the level of C_0_specialized was not possible due to too much overhead.

Good thing is the class A is not big, but still it would be preferable to specialize only void create().

I found this resource very useful for explaining differences between explicit and partial specialization of templates.

1
Well the compiler is right. You need to pass actual types rather than N1 and N2. It's your choice.stefan
@stefan is there a way to get the right syntax for that within the template C_0 rather moving it up to the concrete instances of C_0 ?Dimon

1 Answers

2
votes

First, you forgot to tell the compiler that N1 and N2 are types

template<class N1, class N2>
void some_namespace::A< C_0<N1, N2> >::create() // line 1151
{
  blah_(&C_0<N1, N2>::get_stuff);
}

This still doesn't work, because there is no class A<C_0<N1,N2>> defined. First declare that. Note: you did define A<T>, but that's the general case, not the specialisation you're not trying to define a member for.

Btw, the following three lines make absolutely no sense whatsover.

template<class N1, class N2>
some_namespace::A< some_namespace::C_0<N1, N2> >
  some_namespace::C_0<N1, N2>::A_;