Use typedef/using from templated base class in derived class

前端 未结 2 566
清酒与你
清酒与你 2021-01-03 03:58

In accessing a using from a base class with a templated base class, I\'ve run into an issue with verbosity if nothing else. In the below code, the derived clas

相关标签:
2条回答
  • 2021-01-03 04:15

    Maybe I'm missing something obvious here, but you can simply use using on the type directly without having to give it a new name:

    template <typename T>
    class Derived : public Base<T>{
    public:
        using typename Base<T>::mytype;
        static mytype func() { return 0;}
    };
    

    You can even decide if the using-declaration for mytype should go into the public, protected or private section.

    0 讨论(0)
  • 2021-01-03 04:25

    This is a well known quirk of the language for which there is no real solution. Lookup in templates is done in two separate steps, during the first phase of lookup before instantiation non-dependent names are resolved to their meanings, while in the second phase dependent names are resolved after instantiation.

    The division of the two phases was included in the language to provide some sanity for the template developer that does not know where the template will be instantiated. The first phase of lookup is done at the point where the template is defined, and it can be reasoned about by the developer at exactly that point. At one point or another, the template will do operations that depend on the arguments, and those cannot be resolved where the template is defined, since the template arguments are not yet fixed. Those names are considered dependent, and lookup is postponed to the second phase, after substitution of the template arguments, so that ADL can kick in.

    How does this relate to your particular problem? When you inherit from a non-template base, the developer has fixed what the base is, and that can be looked up at the point of the template definition as you expect. But when the base depends on a template argument, the definition of the base class is not known at the place of the derived template definition. In particular, without substituting the type in, the compiler cannot possibly know whether there is a specialization for this particular type. This implies that during the first phase the compiler cannot assume anything at all about the base and thus lookup cannot search into it.

    The direct way of using a typedef in a base is for the developer of the derived template to explicitly tell the compiler that it wants a type and that the type will be defined in the instantiation of the base template. The key point here is that the compiler knows nothing about the base, but the developer can require that uses of this template comply with a contract in which the instantiation of the base must have that nested type. The developer is free to add constraints on the types of her template, the compiler is not.

    The syntax for that is the one in your first block: typename Base<T>::type to refer to the type, which tells the compiler that the contract of use requires that whatever T is used to instantiate Derived, the user is required to ensure that Base<T> will contain a nested member type that is a type (typename). As a short hand, you can opt for the second approach: create a local typedef that will be found inside Derived and resolved to that. In that case, regular lookup during the first phase will find the nested typedef, determine that it refers to a dependent name and postpone the complete lookup for the second phase.

    While this is not an answer to the question of whether there is a better way (readability wise), I hope it provides some understanding as of why things are like they are. The decision while designing the language was not arbitrary [it might or not be ideal, some people believe the first phase is unneeded and unwanted, but it was not arbitrary]

    0 讨论(0)
提交回复
热议问题