【问题标题】:C++ inherit template dependable typesC++ 继承模板依赖类型
【发布时间】:2014-12-31 21:33:07
【问题描述】:

我有一个模板和许多派生类。在所有这些类中,我想使用模板类型和它的一些依赖类型(实际上我有很多类型和许多依赖类型)。

以下方法很糟糕,因为我需要手动继承(使用关键字)父类的所有类型(参见代码示例):

编辑:我不知道我想使用类型的类也是一个模板很重要。我相应地更新了代码示例。

template<class T>
class A {
  using TBase = T;
  using TDerived = T[10];
}

template<class T>
class B : A<T> {
  // NOTE i want the types TBase and TDerived here and in further children
  using TBase    = A<T>::TBase;
  using TDerived = A<T>::TDerived
}

class C : B<int> {
  // NOTE i want the types TBase and TDerived here and in further children
  using TBase    = B<int>::TBase;
  using TDerived = B<int>::TDerived
}

我还考虑了模板化命名空间,以便我可以在类之外定义类型 - 但它们不存在。

有人有更好的主意吗?

解决方案 1:修复当前方法
(基于 Jan Hudec 的 cmets 和 Oguk 的答案)

  1. 公共继承
    我忘记了类的关键字public:(结构默认是公共的)。
  2. 缺少typename
    在误导性的类中使用我的(错误)类型的编译器警告(尽管using 关键字的那些直接暗示缺少typename keyword)。
    关于何时使用typename 的更多说明可以在这里找到:https://stackoverflow.com/a/7923419/3779655
  3. 类型交互
    当我正确指定类型时(例如,参见 2.missing typename),我也可以使用当前的类名。

结果代码:

template<class T>
class A {
public:
  using TBase = T;
  using TDerived = T[10];
};

template<class T>
class B : public A<T> {
public:
  // possiblity 1:
  using TBase = typename B::TBase;
  TBase memberB1;
  // possibility 2
  typename B::TBase memberB2;
};

class C : public B<int> {
public:
  // NOTE C is no template -> we don't have to do anything
  TBase memberC;
};

解决方案2:特征类
(基于Oguk的回答)

  1. 使用模板化特征类而不是命名空间
    这提供了几乎相同的功能。
  2. 类型信息的不同可用性
    我以前没有想到的一件事是检查哪些类型信息在哪里可用,以及是否需要更多字符才能从父类中检索所需的类型信息(请参阅 NOTE cmets)。

见下面的代码:

template<class T>
struct TypesContainer {
  using TBase = T;
  using TDerived = T[10];
};

template<class T>
class A {
public:
  // TODO possible to directly inherit all types?
  //using TypesContainer<T>;

  // NOTE this is only possible for methods, not types
  using Types = TypesContainer<T>;
  typename Types::TBase memberA;
};

class B : public A<int> {
public:
  // NOTE here I have all template information via definition (by hand)
  using Types = TypesContainer<int>;
  typename Types::TBase memberB;
};

class C : public B {
public:
  // NOTE here I don't have the type information any more
  using Types = TypesContainer<A::Types::TBase>;
  typename Types::TBase memberC;
};

问题:
有没有办法在类范围内直接继承命名空间/类的所有成员(参见 TODO 注释)。使用 using 关键字而不使用赋值运算符 = 仅适用于 methods 而不是 namespacesclassestypes

【问题讨论】:

  • B 类自动继承 TBase 和 TDerived,您无需执行任何操作。但是如果你私下继承A&lt;int&gt;,它们是私有的,所以后代看不到它们;你需要公开继承(如果你愿意,你也可以继承 protected,但我不确定这是否有意义)。
  • 请注意,如果 B 类是模板并且基类依赖于参数,则您必须限定继承的类型。但是 IIRC 用B:: 对它们进行限定应该可以工作。
  • @JanHudec 感谢您的回答。很抱歉我不能投票给他们,因为我没有足够的声誉:(
  • using 当然应该适用于类型。
  • @JanHudec 我的意思是在没有等号的情况下使用它,就像我在解决方案2 (using TypesContainer&lt;T&gt;;) 中的 TODO 评论之后一样。这样做(有或没有typename)会导致编译器错误error: expected nested-name-specifier!

标签: c++ templates inheritance using


【解决方案1】:

首先,如果您的设计在其他方面没有问题,那么如果您公开继承基类,它应该可以工作。这将适用于您发布的代码。但是,如果您的示例非常简化,则可能还有另一个原因是您无法在真实代码中访问 typedef:如果您的派生类实际上也是一个模板类,那么可能会给您带来问题也是一个模板类使用类型参数T,例如B&lt;T&gt;。这将使基类A&lt;T&gt; 依赖 如果您使用非依赖名称(即仅TBase)在B&lt;T&gt; 中引用它们,则在查找期间不会考虑其成员,所以他们不会被发现。将它们称为typename A&lt;T&gt;::TBase 将通过使名称依赖名称来解决该问题。

如果您想遵循您的其他想法并在类之外提供该类型信息(因为它在概念上更多地与T 相关联,而不是与A 类相关),而不是“模板化命名空间" 你在想,通常 trait 类用于此目的:

template <class T>
struct MyTraits {
    using TBase = T;
    using TDerived = T[10];
}

然后,您可以使用MyTraits&lt;T&gt;::TBase 从任何地方访问这些using 声明(或typedefs)。这实际上是您使用模板化命名空间所能实现的。如果在依赖上下文中使用 MyTraits 的 using/typedef 成员,请不要忘记添加 typename 关键字,即 typename MyTraits&lt;T&gt;::TBase

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    相关资源
    最近更新 更多