7

在使用using模板化基类从基类访问 a 时,如果没有其他问题,我遇到了冗长的问题。在下面的代码中,派生类尝试使用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;}
};

然而,在实践中,我发现这是一个非常多的字符,因为它看起来应该更简单。如果 Base 类没有被模板化,那么它就不需要 the<T>或 typename (显然)。

在我真正的问题中,我有很多从基础派生的类,如果可能的话,我想简化它。我现在拥有的就像下一个示例一样,我只是添加了一个附加using功能以从基类中获取类型,但感觉就像是我不需要的额外层。

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

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

4

2 回答 2

15

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

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

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

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

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

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

于 2013-11-06T16:11:30.953 回答
6

也许我在这里遗漏了一些明显的东西,但是您可以直接using在类型上使用而无需给它一个新名称:

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

您甚至可以决定是否应该将using-declaration formytype放入public,protectedprivate部分。

于 2013-11-06T17:23:15.890 回答