在派生类中使用 typedef/using from 模板化基类

Use typedef/using from templated base class in derived class

本文关键字:from using 基类 typedef 派生      更新时间:2023-10-16

在从具有模板化基类的基类访问using时,如果没有别的,我遇到了冗长的问题。 在下面的代码中,派生类尝试使用其基类中的my_type

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;}
};

然而,在实践中,我发现这是一个非常多的字符,似乎它应该更简单。 如果基类不是模板化的,那么它不需要<T>或类型名(显然)。

在我的实际问题中,我有大量从基础派生的类,如果可能的话,我想简化它。 我现在拥有的就像下一个示例一样,我只是添加一个额外的using来从基类中获取类型,但它感觉就像一个我不需要的额外层。

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

这似乎是一个愚蠢的问题,但是基类的mytype在派生类中使用次数使得它在前一种情况下非常可怕。 有没有一种正确的方法可以将类型从模板化基础中取出以保持可读性?

这是语言的一个众所周知的怪癖,没有真正的解决方案。模板中的查找分两个单独的步骤完成,在实例化之前的查找第一阶段,非依赖名称被解析为其含义,而在第二阶段,从属名称在实例化解析。

语言中包含这两个阶段的划分,以便为不知道模板将在哪里实例化的模板开发人员提供一些理智。查找的第一阶段是在定义模板的位置完成的,开发人员可以在该点进行推理。在某一时刻,模板将执行依赖于参数的操作,并且由于模板参数尚未固定,因此无法在定义模板的位置解析这些操作。这些名称被视为依赖名称,在替换模板参数后,查找将推迟到第二阶段,以便 ADL 可以启动。

这与您的特定问题有何关系?当您从非模板基继承时,开发人员已经修复了基数是什么,并且可以按预期在模板定义点查找。但是,当基依赖于模板参数时,基的定义在派生模板定义的位置是未知的。特别是,如果不替换类型,编译器就不可能知道此特定类型是否存在专用化。这意味着在第一阶段,编译器根本无法假设有关基础的任何内容,因此查找无法搜索它。

在基中使用 typedef 的直接方法是派生模板的开发人员显式告诉编译器它需要一个类型,并且该类型将在基模板的实例化中定义。这里的关键点是编译器对 base 一无所知,但开发人员可以要求此模板的使用符合协定,在该协定中,基的实例化必须具有该嵌套类型。开发人员可以自由地对模板的类型添加约束,而编译器则不能。

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

虽然这不是对是否有更好的方法(可读性明智)的问题的答案,但我希望它能提供一些理解,说明为什么事情会这样。设计语言时的决定不是任意的[它可能理想,也可能不理想,有些人认为第一阶段是不需要和不想要的,但它不是任意的]

也许我在这里错过了一些明显的东西,但您可以直接在类型上使用using,而无需为其指定新名称:

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

您甚至可以决定mytypeusing声明是否应该进入publicprotectedprivate部分。