在派生类中使用typedef /使用模板化的基类 [英] Use typedef/using from templated base class in derived class

查看:174
本文介绍了在派生类中使用typedef /使用模板化的基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用带有模板基类的基类访问时,我遇到了一个问题,如果没有别的。在下面的代码中,派生类试图从其基类中使用 my_type

 code> template< typename T> 
class Base {
public:
using mytype = T;
};

template< typename T>
class Derived:public Base< T> {
public:
//使用基本的mytype here
static typename Base< T> :: mytype func(){return 0; }
};

但是,实际上我发现这是一个可怕的很多字符应该更简单。如果Base类不是模板化的,则它不需要< T> 或类型名(显然)。



在我真正的问题,我有很多类派生自基地,我想简化这如果可能的话。我现在所拥有的就像下一个例子,我只是添加一个额外的使用从基类获取类型,但它感觉像一个额外的层

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

这可能看起来像一个愚蠢的问题,但基类的 mytype 在派生类中使用,使得它在前一种情况下很可怕。

解决方案

是否有正确的方法从模板库中获取类型?这是一个众所周知的语言的奇怪,没有真正的解决方案。在模板中的查找在两个单独的步骤中完成,在之前的查找的第一阶段期间,非依赖名称被解析为它们的含义,而在第二阶段,依赖名称在

两个阶段的划分包含在语言中,为模板开发人员提供了一些理性,模板开发人员不知道模板将在哪里实例化。第一阶段的查找是在定义模板的地方完成的,它可以由开发人员在恰当的时间点进行推理。在一个点或另一个点,模板将执行依赖于参数的操作,并且那些不能在模板被定义的地方被解析,因为模板参数尚未固定。这些名称被认为是依赖的,并且在替换模板参数之后,将查找推迟到第二阶段,以便ADL可以引入。



这与您的特殊问题?当您从非模板基础继承时,开发人员已经固定了基础,并且可以按照预期在模板定义点查找。但是当基础依赖于模板参数时,基础的定义在派生模板定义的位置是未知的。特别是,没有替换类型,编译器不可能知道是否有一个特殊类型。这意味着在第一阶段编译器不能假定任何关于基础的任何东西,因此查找不能搜索它。



在基础中使用typedef的直接方法是为派生模板的开发人员明确告诉编译器它想要一个类型,并且类型将在基本模板的实例化中定义。这里的关键是编译器不知道底层,但开发人员可以需要该模板的使用符合合同,其中基础的实例化必须有嵌套类型。开发人员可以对她的模板类型自由添加约束,编译器不是。



这是第一个块中的语法: typename Base< T> :: type 来指代类型,它告诉编译器使用契约要求 T 用于实例化 Derived ,用户需要确保 Base< T> 将包含嵌套成员 type 是一种类型( typename )。简而言之,您可以选择第二种方法:创建一个本地typedef,它将在 Derived 中找到并解析为。在这种情况下,在第一阶段期间的常规查找将找到嵌套的typedef,确定它引用依赖名称并推迟第二阶段的完整查找。



While这不是一个问题的答案,是否有一个更好的方式(可读性明智),我希望它提供一些理解,为什么事情就像他们是。在设计语言时的决定不是任意的(它可能或不是理想的,有些人认为第一阶段是不需要的和不需要的,但它不是任意的]


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 class attempts to use the my_type from its base class.

template <typename T>
class Base {
    public:
        using mytype = T;
};

template <typename T>
class Derived : public Base<T>{
    public:
        // using the base's mytype here
        static typename Base<T>::mytype func() { return 0;}
};

However, in practice I'm finding this to be an awful lot of characters for what seems like it should be simpler. if the Base class was not templated then it wouldn't require the <T> or the typename (obviously).

In my real issue, I have a great deal of classes deriving from the base and I want to simplify this if possible. What I have at the moment is like the next example, where I'm just adding an additional using to get the type from the base class, but it feels like an extra layer that I shouldn't need to have.

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

this may seem like a silly issue, but the number of times the base class's mytype is used in the derived classes makes it pretty hideous in the former case. Is there a right way to get the types out of the templated base that maintains readability?

解决方案

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]

这篇关于在派生类中使用typedef /使用模板化的基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆