为什么我们需要为每个类函数定义指定类型模板参数



既然我们在类声明上定义模板类型,为什么我们必须在每个函数定义之后指定它?我很困惑,因为它甚至在同一个文件中,所以似乎几乎没有必要在每个函数上都指定它,而且因为我们使用的是::运算符,所以它不应该回到类声明,并看到T已经定义好了。

我刚接触c++,还需要澄清一些误解。

#ifndef __Foo_H__
#define __Foo_H__
template <class T>
class Foobar{
  private:
    bool foo1(T);
    bool foo2(T);
  public:
   FooBar();
};
template <class T> bool FooBar<T>::foo1(T data){
 code..
}
template <class T> bool FooBar<T>::foo2(T data){
 code..
}
#endif

首先,您可以将参数重命名为普通函数:

template <class U> bool FooBar<U>::foo1(U and_here_too){/**/}

它还能够处理(部分)专业化:

template <> bool FooBar<int>::foo1(int i){/**/}
template <typename T> bool FooBar<std::vector<T>>::foo1(std::vector<T> v){/**/}

模板是泛型编程的示例。这个想法是重用代码/算法。在具有严格类型控制的语言中,您会遇到看似不必要的约束。例如,您可能有一些排序函数在一个项目中做得很好,但与另一个项目使用的类型不兼容。

C++、C#和Java引入了通用编程作为模板(C++)和泛型(C#、Java)。在泛型(让我们来谈谈Java)中,类是现有的实体,类参数主要用作类型控制服务。这就是他们收藏的目的。当您检查列表的工作方式时,您会看到列表聚集了对象,并且只有在检索到对象时才强制转换回参数化类型。当您编写类时,您只能假设参数化类型是Object或声明的接口,如以下示例所示:

class Test<T extends Comparable> {}

在这里,您可以使用T作为Comparable。除非显式声明接口,否则参数将被视为Object。

现在是泛型和模板之间的区别。在C++中,您可以对实现中的参数化类型进行更多假设。您可以编写未知类型对象的排序。在Java中,您至少必须知道什么是接口参数类型。这导致C++必须为每个参数构建新的类(以便检查代码是否正确)。Vector<int>**是与**Vector<float>完全分离的类型。Java中存在一个类Vector<? extends Comparable>

::是作用域运算符。您可以访问Vector<int>的作用域,因为类存在,但Vector不存在。

因此,Java可以编译泛型,而C++不能。所有模板都必须在标题中提供给所有程序员;你不能隐藏它(有一些工作要编译模板,但我不知道它的状态是什么)。

因此,当您使用泛型时,您可以引用方法Vector.add(),而当使用模板时,您必须指定参数template<class T> Vector<T>

PS。由于模板参数是类名的组成部分,您可以使用模板进行编译时的计算,如斐波那契序列

template<int N> struct Fibonaci {
  static const int element = Fibonacci<N-1>::data + Fibonacci<N-2::data>;
}
template<1> struct Fibonaci {
  static const int element = 1;
}
template<0> struct Fibonaci {
  static const int element = 0;
}

最新更新