【问题标题】:C++ template inheritance issue with base types基本类型的 C++ 模板继承问题
【发布时间】:2010-09-21 08:49:27
【问题描述】:

我有以下代码,编译失败

template < typename T >
class Base
{
public:

    typedef T * TPtr;

    void func()
    {
    }
};

template < typename T >
class Derived : public Base< T >
{
public:
    using Base< T >::TPtr;
    using Base< T >::func;

    TPtr ptr;
};

int main( int c, char *v[] )
{
    Derived< int > d;
    d.func();
}

编译器发出以下命令。

t.cpp:16: error: 'TPtr' does not name a type
t.cpp:16: note: (perhaps 'typename Base<T>::TPtr' was intended)

现在我知道我可以按照编译器的建议做,但我不明白为什么

    using Base< T >::TPtr;

没用。

如果我注释掉“TPtr ptr”行,那么它会编译,证明“using Base&lt; T &gt;::func;”语句有效。

有什么想法吗?

【问题讨论】:

  • 我不认为using Base&lt;T&gt;::func; 做你认为它做的事情,d.func() 工作正常,因为它是从父类继承的。你有什么理由不能做typedef Base&lt;T&gt;::TPtr TPtr
  • 我必须使用“typedef typename Base::TPtr TPtr”,但正如我对 Konrad 的评论,是的,这是可行的,但如果我必须这样做的话,它有点违背了继承的目的基于基类定义新类型。

标签: c++ templates inheritance


【解决方案1】:

Base&lt; T &gt;::TPtr 是一个所谓的依赖名称,因此您需要在它前面加上typename 才能使声明生效。

此外,using 不适用于 typename,因此您需要改用 typedef

typedef typename Base<T>::TPtr TPtr;

问题在于编译器无法决定——不知道T 是什么! – TPtr 在此上下文中是否命名类型或变量/函数。为避免歧义,它始终假定为后者,除非另有明确说明(因此需要typename)。

【讨论】:

  • 我试过“typename TPtr ptr;”这仍然失败。 “TPtr 之前的预期嵌套名称说明符”
  • @Scary:我的错误。更新了答案,现在再试一次。
  • 是的,我同意这行得通。但是,如果我必须基于基类型定义一个新类型,这有点违背继承的目的。
  • +1:谢谢康拉德,很长一段时间以来,我都希望自己知道并理解这一点。现在由您清楚地说明和解释。我会尽快使用它。
  • 我认为更合适的名称是“依赖名称”而不是“依赖类型”。
【解决方案2】:

这是缺陷的一部分。虽然 C++03 确实提供了 using typename,但它确实没有提供了必要的规则来说明 using 声明所声明的名称是类型名称。它只是提供了一个工具来说明在 using 声明中引用的名称是一个类型名称。因此,您实际上可以执行以下操作,但编译器的成功率各不相同。有些会让它工作,但有些不会。

template < typename T >
class Derived : public Base< T >
{
public:
    using typename Base< T >::TPtr;
    using Base< T >::func;
      // up to here it's alright
    TPtr ptr;
      // but this may only work on some compilers
};

This issue 已针对 C++0x 修复。对于 C++03,解决方法是改用 typedef

【讨论】:

    【解决方案3】:

    我不明白为什么:
    使用 Base::TPtr;
    不工作。

    由于可能的模板特化,Base&lt; T &gt;::TPtr 可以是任何东西:类型名称、变量名称、函数等。

    使用关键字typename 告诉编译器它只能是类型名称。

    Here is a decent explanation 它可以解决什么样的歧义。向下滚动到“问题”,它准确地涵盖了您的情况。

    【讨论】:

      【解决方案4】:

      当你写作时 TPtr ptr;

      它被视为Base&lt;T&gt;::TPtr,编译器将假定这是Base&lt;T&gt; 的成员变量或Base&lt;T&gt; 的方法(这是它要做的,因为Base&lt;T&gt;::TPtr 是一个“从属名称”并且不幸的是,在这种情况下,编译器将假定变量或函数而不是类型),从而使声明无效。

      关键字typename 允许编译器明确知道TPtr 命名了一个类型。

      【讨论】:

      • 不,这是错误的:编译器不会假定它是static——事实上,同样的声明适用于func,它也不是static
      • 见上面的评论。我尝试使用“typename TPtr ptr;”并且还尝试了“使用 typename Base::TPtr”,但都失败了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多