mercredi 24 mai 2017

Inheriting with default template parameter of nested class within template outer class

I have a template outer class (Outer below) with a public template nested class (Inner). The template parameter of Inner has a default. I specialize Outer (SpecializedOuter), then derive from the nested class (SpecializedOuter::Inner) to define a new class (SpecializedInner). Compilation is fine if I specify Inner's template parameter in the definition of SpecializedInner. However, g++ won't compile the code if I omit Inner's template parameter in SpecializedInner, even though a default is specified (Inner<U=void>).

Is there any way to fix this for both g++ and VS2013? I have looked through Google results and other questions but am having trouble getting search terms that will distinguish all of the possible uses of "default" and "template" from each other :) .

Code and error messages

The following test.cpp compiles with no errors or warnings on g++ 5.4.0, g++ -std=c++11 -Wall -c test.cpp -o test.o:

template<typename T>
class Outer {
public:
  template<typename U = void>   // The default I want to take advantage of
  class Inner {
    Outer *outer_;
  public:
    Inner(Outer *outer): outer_(outer) {}
  };
}; //Outer

typedef Outer<int> SpecializedOuter;

class SpecializedInner: public SpecializedOuter::Inner<void> { 
    // also works with int or double instead of void - I just have to specify some type.
public:
  SpecializedInner(SpecializedOuter *so)
    : SpecializedOuter::Inner<void>(so)     // type also expressly specified here
  {}
};

However, if I remove <void> from public SpecializedOuter::Inner<void> and : SpecializedOuter::Inner<void>, I get compilation errors. I would expect that the compiler would use the default typename U = void from the definition of Inner. Code and errors are:

// ... definitions of Outer, Inner, SpecializedOuter as above ...
class SpecializedInner: public SpecializedOuter::Inner { // without <void> 
    // => "expected class-name before `{' token"
public:
  SpecializedInner(SpecializedOuter *so)
    : SpecializedOuter::Inner(so)     // without <void> 
    // => "expected class-name before `(' token" 
    // => "expected `{' before `(' token"
  {}
};

Use case

In case you are wondering, in my use case, Outer is a subclass of OpenSceneGraph's osg::Geometry and Inner is a subclass of osg::Drawable::UpdateCallback. I am trying to move boilerplate into Inner for convenience, and remove the need for a dynamic_cast from osg::Geometry to Outer<T>.

Aucun commentaire:

Enregistrer un commentaire