2

I have the following simplified program:

class Base { };

template < typename T >
class X: public T
{
    public:
        using TOP = T;
};

// with dependent template parm    
template < typename T >
class Y: public X< T >
{
    // I have to write down the full name of the base class
    using X<T>::TOP::operator =;
};

// without depending template parameter
template < typename T >
class Y: public X< Base >
{
    // I simply can use the defined type from the base class
    using TOP::operator =;
};


int main()
{
    Y< Base > y ;
}

The question is now, if there is any way to simplify the full repetition of the base class type. My original code is something like that:

template < typename VAR_TYPE >
class VarObserved: public ConstructAll2<
                   UsingHelperV_None,
                   UsingHelper_None,
                   CONTAINERL< AssignConst >,
                   CONTAINERL< Print >,
                   CONTAINERL< DataStore >,
                   CONTAINERL< Distribute_ >,
                   CONTAINERL< EndForward >,
                   CONTAINERSP< DataStoreBase, VAR_TYPE >
                   >
{
    public:
        using SELF = ConstructAll2<
            UsingHelperV_None,
            UsingHelper_None,
            CONTAINERL< AssignConst >,
            CONTAINERL< Print >,
            CONTAINERL< DataStore >,
            CONTAINERL< Distribute_ >, 
            CONTAINERL< EndForward     >,
            CONTAINERSP< DataStoreBase, VAR_TYPE >   // see text 1)
                >;

        VarObserved( const VAR_TYPE& var ): SELF{{ var }}{}
        using SELF::AssignConst::operator=;
};

As you can see, the full repetition of all the template parameters is not very "nice". Any chance to fix that?

If above code has no dependent template parameter ( change the single line 1.) ) from the example above to:

CONTAINERSP< DataStoreBase, int>

the class becomes totaly simple and much more easy to maintain:

...
VarObserved( const VAR_TYPE& var ): ConstructAll2{{ var }}{}
using AssignConst::operator=;
....

As a reference to the underlying problem I found already that question

"not declared in this scope" error with templates and inheritance

but no idea to simplify my code.

Klaus
  • 24,205
  • 7
  • 58
  • 113

3 Answers3

2

Maybe using a new template parameter with a default value (corrected following a Justin's observation )?

template <typename VAR_TYPE, typename CA2 = ConstructAll2<
                   UsingHelperV_None,
                   UsingHelper_None,
                   CONTAINERL< AssignConst >,
                   CONTAINERL< Print >,
                   CONTAINERL< DataStore >,
                   CONTAINERL< Distribute_ >,
                   CONTAINERL< EndForward >,
                   CONTAINERSP< DataStoreBase, VAR_TYPE >>>
class VarObserved : public CA2
 {
    public:
        using SELF = CA2;

        VarObserved( const VAR_TYPE& var ): SELF{{ var }}{}
        using SELF::AssignConst::operator=;
 };
max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    One disadvantage of this approach is that `ConstructAll2< ... >` ends up in the symbol name. – Justin Jul 15 '19 at 17:34
  • 1
    @Justin - "Why the template specialization?" - Because I've confused myself mixing two different ideas. Corrected; thanks. – max66 Jul 15 '19 at 18:29
  • I thought I already tried exactly that before and the compiler was not lucky... if that works, it would be the best approach, as it needs no split of the definition. I will check tomorrow on my "monster" template :-) Thanks! – Klaus Jul 15 '19 at 18:49
2

The question is now, if there is any way to simplify the full repetition of the base class type.

To find the name TOP declared in the dependent base class, you can write Y::TOP instead of X<T>::TOP, although since this may confuse readers, you should probably put a comment about why you are doing this.

The reason why this works is that it's, well, no longer unqualified lookup. Note that you don't need to write the template arguments out here (Y is the injected class name, and means the same thing as Y<T>).

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Wow, that makes it totally simple! Simply replicate the class name without template parameters is nice! But gives a interesting syntax for the constructor: `VarObserved( const VAR_TYPE& var ): VarObserved::ConstructAll2{{ var }}{}` – Klaus Jul 15 '19 at 20:00
1

In addition to the idea from max66 I found also the following solution, not based on specialization but on template template parameter:

template < typename VAR_TYPE >
using VarObserved_Parms = ConstructAll2<
    UsingHelperV_None,
    UsingHelper_None,
    CONTAINERL< AssignConst >,
    CONTAINERL< Print >,
    CONTAINERL< DataStore >,
    CONTAINERL< Distribute_ >,
    CONTAINERL< EndForward >,
    CONTAINERSP< DataStoreBase, VAR_TYPE >
    >;

template < typename VAR_TYPE, template <typename> class COMPONENTS >
class VarObserved2: public COMPONENTS< VAR_TYPE >
{
    using SELF = COMPONENTS< VAR_TYPE >;

    VarObserved2( const VAR_TYPE& var ): SELF{{ var }}{}
    using SELF::AssignConst::operator=;
};

After I got the idea from Brian, all implodes to nearly nothing:

template < typename VAR_TYPE >
class VarObserved: public ConstructAll2<
                   UsingHelperV_None,
                   UsingHelper_None,
                   CONTAINERL< AssignConst >,
                   CONTAINERL< Print >,
                   CONTAINERL< DataStore >,
                   CONTAINERL< Distribute_ >,
                   CONTAINERL< EndForward >,
                   CONTAINERSP< DataStoreBase, VAR_TYPE >
                   >
{
    public:
        VarObserved( const VAR_TYPE& var ): VarObserved::ConstructAll2{{ var }}{}
                                            ^^^^^^^^^^^^^ never saw that before, interesting syntax ;)
        using VarObserved::AssignConst::operator=;
};
Klaus
  • 24,205
  • 7
  • 58
  • 113
  • 1
    Why do you need a template template parameter? Why not skip it and use `VarObserved_Params` directly? – Justin Jul 15 '19 at 17:35