【问题标题】:When should I use the keyword "typename" when using templates使用模板时应该何时使用关键字“typename”
【发布时间】:2011-05-12 18:52:36
【问题描述】:

我最近一直在做一个小项目,但我想不通..

我得到了一个 .h 文件,其中包含一个使用类型名模板的类。在那个班级里面有一个私人班级。

template <typename T>
class Something
{
public:
        Something();
        ~Something();

        Node* Function1(int index);
        int Index(const T& id);


private:
        class Node()
        {
                public:
                T id;

                //Imagine the rest for the Node


        };      
};

当我想定义“Something”类的功能时出现问题

这是我的做法(在 .inl 文件中)

template<typename T>
Node* Something::Function1(int index) //Is the return type well written?
{
        // returns the node at the specified index
}

template<typename T>
int Something::Index(const T& id) //Is the parameter type well specified?
{
        // returns the index of the node with the specified id
}

所以错误部分在定义部分...我是否必须告诉编译器返回类型(在本例中为 Node*)使用类型名模板(如:typename Node*)?那么参数呢? typename const Node&amp;?

所以基本上,我什么时候必须指定函数/参数是否使用模板?

感谢您的宝贵时间。

【问题讨论】:

  • 请在您的问题中发布sinppets!
  • 我已经发布了带有 sn-ps 的链接。我不知道如何正确缩进我的 sn-ps。

标签: c++ templates syntax typename


【解决方案1】:

简单的规则:如果Class 部分依赖于模板参数,则每次使用Class::Type 语法命名类型时都需要使用typename 关键字。 (Class 部分可能是模板参数,也可能是您的类模板中的 typedef 等)

编辑:关于嵌套类范围规则也有一些混淆。这主要与typename 问题无关,所以这里是一个非模板示例。

class Outer {
public:
  class Inner {
  };
  Inner* func(Inner* obj);
};

Outer::Inner* func(Inner* obj)
{
}

Inner的全称是Outer::Inner。但是您也可以在类Outer 范围内的任何地方使用较短的名称Inner,包括func 的所有声明。在func的定义中,返回类型不在Outer的范围内,所以需要全名。但是(后面的函数参数都在Outer的范围内,所以简称就可以了。

将此与原始示例的模板性结合起来,由于 Outer 的等价物是 Something&lt;T&gt;,因此您需要使用 typename 关键字来表示 Something&lt;T&gt;::Node。

【讨论】:

  • 所以函数Index定义中的参数类型应该写成typename const Class::Node& id ?
  • @Pacane:这取决于,您要传递T 还是Node?如果你确实想传递一个Node,完整版可以工作,但不是必需的,因为编译器刚刚看到你定义了一个Something 方法,const Node&amp; 就可以了。
  • 感谢您的解释,并抽出时间。
  • 在成员定义中添加了类范围的解释。
【解决方案2】:

typename和class在模板类型参数列表中是等价的:

template <class T> class C;

和

一样
template <typename T> class C;

需要typename 的地方是指dependent names:

template <typename T> struct A {
    typedef typename T::some_type container;
};

【讨论】:

  • 实际上,typename 和 class 在参数列表中是不等价的。需要模板模板参数时,typename 关键字不能替换 'class'。
  • 是的,谢谢,忘了这个。尽管这只是语言方面的嘘声-他们只是忘记了与我在这里相同的情况:)
【解决方案3】:

对于Function1,您需要告诉编译器Node 是什么——在这种情况下,它是Something&lt;T&gt; 中的嵌套类型。因为它依赖于T(它是一个依赖名称),所以你需要告诉编译器它是一个类型,所以你必须写成typename Something&lt;T&gt;::Node。问题是,可能有一些T 实际上不是Something&lt;T&gt;::Node 的类型(即,如果您部分专门化Something&lt;T&gt;)。

对于Index,你所拥有的很好——const T&amp; 只是对const T 的引用,编译器知道T 是什么。

【讨论】:

  • 所以如果参数是指向节点的指针,我必须再次指定 typename 部分,对吧?
  • 由于您在Something&lt;T&gt; 内,您可以直接写Node *。但如果你明确写出来,你需要说typename Something&lt;T&gt;::Node * 而不仅仅是Something&lt;T&gt;::Node *。
  • 感谢您的解释和抽出时间。
【解决方案4】:
template<typename T>
typename Something<T>::Node * Something::Function1(int index) //Is the return type well written?
{
        // returns the node at the specified index
}

【讨论】:

  • 好的,那其他方法的参数类型呢?
  • Node 是一个嵌套类名。因此,除非您使用 Something&lt;T&gt; 方法的代码或使用完整的 typename Something&lt;T&gt;::Node 名称,否则您不能使用它。并且方法返回类型(在类外部定义)还不是“在”Something 的方法中,因此您必须向编译器说明。另一种方法不会有任何此类问题,因为编译器总是知道int 的含义。
  • 感谢您的解释和抽出时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-02
  • 2011-05-24
  • 1970-01-01
  • 2011-06-30
  • 2014-01-30
相关资源
最近更新 更多