为什么不允许在非推导上下文中使用基类定义,以及如何解决这个问题? [英] Why is using base class definitions in non-deduced context not permitted, and how to get around this?

查看:28
本文介绍了为什么不允许在非推导上下文中使用基类定义,以及如何解决这个问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

#include <iostream>

template <typename T>
struct Base
{
    using Type = int;
};

template <typename T>
struct Derived : Base<T>
{
    //uncommmenting the below cause compiler error
    //using Alias = Type;
};

int main()
{
    Derived<void>::Type b = 1;
    std::cout << b << std::endl;

    return 0;
}

现在类型名 Type 可用于 Derived 如果它在推导的上下文中 - 如 b 的完全有效声明所示.但是,如果我尝试在 Derived 本身的声明中引用 Type,那么我会收到一个编译器错误,告诉我 Type 没有命名类型(例如,如果 Alias 的定义未注释).

Now the typename Type is available to Derived if its in a deduced context - as shown by the perfectly valid declaration of b. However, if I try to refer to Type inside the declaration of Derived itself, then I get a compiler error telling me that Type does not name a type (for example if the definition of Alias is uncommented).

我猜这与编译器在解析Derived的定义时无法检查是否可以从基类中提取Type有关code> 在参数 T 的特定实例化的上下文之外.在这种情况下,这是令人沮丧的,因为 Base 总是 定义 Type 而不管 T.所以我的问题是双重的:

I guess this is something to do with the compiler not being able to check whether or not Type can be pulled in from the base class when it is parsing the definition of Derived outside the context of a specific instantiation of parameter T. In this case, this is frustrating, as Base always defines Type irrespective of T. So my question is twofold:

1).为什么会发生这种情况?我的意思是,编译器为什么要在实例化上下文(我猜是非推导上下文)之外解析 Derived ,而不这样做会避免这些虚假"编译器错误?也许这是一个很好的理由.标准中规定必须发生这种情况的规则是什么?

1). Why on Earth does this happen? By this I mean why does the compiler bother parsing Derived at all outside of an instantiation context (I guess non-deduced context), when not doing so would avoid these 'bogus' compiler errors? Perhaps there is a good reason for this. What is the rule in the standard that states this must happen?

2).对于这种类型的问题,有什么好的解决方法?我有一个实际案例,我需要在派生类的定义中使用基类类型,但由于此问题而无法这样做.我想我正在寻找某种隐藏在非推导上下文后面"的解决方案,我通过将所需的定义/类型定义放在模板化类或类似的东西后面来防止这个编译器第一次通过".

2). What is a good workaround for precisely this type of problem? I have a real-life case where I need to use base class types in the definition of a derived class, but am prevented from doing so by this problem. I guess I'm looking for some kind of 'hide behind non-deduced context' solution, where I prevent this compiler 'first-pass' by putting required definitions/typedefs behind templated classes or something along those lines.

正如下面的一些答案所指出的,我可以使用using Alias = typename Base::Type.我应该从一开始就说,我知道这是有效的.然而,它并不完全令人满意,原因有两个:1)它根本不使用继承层次结构(Derived 不必从 Base 派生出来才能工作),而我正是在尝试使用在我的基类层次结构中定义的类型,并且 2) 实际案例实际上有多层继承.如果我想从几层中提取一些东西,这会变得非常丑陋(我要么需要引用一个非直接祖先,要么在每一层重复 using 直到我到达我需要它在)

As some answers below point out, I can use using Alias = typename Base<T>::Type. I should have said from the outset, I'm aware this works. However, its not entirely satisfactory for two reasons: 1) It doesn't use the inheritance hierarchy at all (Derived would not have to be derived from Base for this to work), and I'm precisely trying to use types defined in my base class hierarchy and 2) The real-life case actually has several layers of inheritance. If I wanted to pull in something from several layers up this becomes really quite ugly (I either need to refer to a non-direct ancestor, or else repeat the using at every layer until I reach the one I need it at)

推荐答案

因为 type 在依赖范围"中,您可以像这样访问它:

Because type is in a "dependent scope" you can access it like this:

typename Base<T>::Type

你的 Alias 应该像这样定义:

Your Alias should then be defined like this:

using Alias = typename Base<T>::Type;

请注意,此时编译器不知道 Base::type 是否描述了成员变量或嵌套类型,这就是关键字 typename 是必需的.

Note that the compiler doesn't, at this point, know if Base<T>::type describes a member variable or a nested type, that is why the keyword typename is required.

你不需要在每一层重复定义,这里有一个例子,link:

You do not need to repeat the definition at every layer, here is an example, link:

template <typename T>
struct intermediate : Base<T>
{
    // using Type = typename Base<T>::Type; // Not needed
};

template <typename T>
struct Derived : intermediate<T>
{
    using Type = typename intermediate<T>::Type;
};

更新

你也可以使用它自己的类,这依赖于使用 unknown专业化.

You could also use the class it self, this relies on using an unknown specializations.

template <typename T>
struct Derived : Base<T>
{
    using Type = typename Derived::Type; // <T> not required here.
};

这篇关于为什么不允许在非推导上下文中使用基类定义,以及如何解决这个问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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