为什么我必须在模板中的每个函数上面声明模板?

时间:2016-06-23 19:20:20

标签: c++ templates

我正在写一个模板,我这样做有点新鲜。我注意到我遇到的每个教程都会在每个实现的函数上面声明模板。我很好奇,如果这是有原因的,如果有办法解决它,以及它是如何有用的。

示例:在某个文件中(我们将其称为template.h):

template <class T> class MyClass
{
public:
    MyClass(T parameter);
    T getParameter() const;
    void setParameter();
    void doSomethingUseless() const;
private:
    T mParameter;
}


template<class T>
MyClass<T>::MyClass(T parameter):mParameter{parameter}
    {}

template<class T>
T MyClass<T>::getParameter() const
    {
        return mParameter;
    }

template<class T>
void MyClass<T>::setParameter(T parameter)
    {
        mParameter = parameter;
    }
template<class T>
void MyClass<T>::doSomethingUseless() const
    {
        for (int i = 0; i < 10000; i++)
    }
  • 为什么每个函数都必须被模板化,如果它与之无关 模板类型? (例如,doSomethingUseless方法)
  • 为什么每个函数都需要template<class T>MyClass<T>来编译它?
  • 我接近这个错误/有更简单的方法吗?

无论如何,谢谢你的期待。作为一个注释,我没有编译上面的例子,我概括了我写的一个不同的模板类(没有一堆繁忙的函数)如果有错误,我道歉。

3 个答案:

答案 0 :(得分:4)

模板类的成员函数本身也是模板。因此,需要使用任何必需的模板参数(在您的情况下为T)定义它们。如果你不这样做,你可能会编写一个函数:

void MyClass::memberFunc(T var) {}

在这种情况下,T是什么?在此范围内没有定义T.

那么人们做什么?许多代码库将简单地定义与类内联的函数。然而,其他人坚持将它们分开,就像你所做的那样。不幸的是,这只是语言的要求。

答案 1 :(得分:2)

模板化类的成员函数需要template,因此即使函数本身不是模板化的,它们也可以指定类的模板。这是因为该类不是class MyClass,而是template<typename T> class MyClass<T>,但默认情况下函数不知道。因此,编译器需要知道类的模板参数是什么,因此它可以将函数与实际类关联,允许它执行诸如生成成员函数的this指针的正确版本之类的事情,或者允许函数使用类的模板参数列表。

这是必要的,因为模板不是原始代码,它们是代码的蓝图,编译器在需要实例化或以其他方式使用它们时使用它来制作实际代码。

template<typename T> class MyClass {};

// ...

MyClass<int>  mci; // Compiler creates class "MyClass_int".
MyClass<bool> mcb; // Compiler creates class "MyClass_bool".

由于这个原因,成员函数也需要模板化,因此编译器也知道将它们用作代码蓝图。

void MyClass::myFunc() {}
// Compiler thinks this explicitly belongs to class "MyClass".
// Can't be used with MyClass_int or MyClass_bool.

template<typename T>
void MyClass<T>::myFunc() {}
// Compiler knows this belongs to class template "MyClass<T>".
// Can be turned into MyClass_int::myFunc() or MyClass_bool::myFunc().

通常,模板参数列表是为整个类的范围定义的,它允许在类中定义的成员函数使用模板而不显式指定它。

template<typename T>
class MyClass {
  public:
    // Every function in here is implicitly "template<typename T>".

    void myInternalFunc(T t) {}
};

但是,如果函数是在类外定义的,则它们不再能够访问隐式模板参数列表,并且需要手动指定它。

template<typename T>
void MyClass<T>::myExternalFunc(T t) {}

请注意,此模板参数列表不是函数的,而是类'。这意味着如果该函数也是模板化的,它需要一个单独的模板参数列表,这显然有点傻。

template<typename T>
class MyClass {
    template<typename U>
    void myTemplatedFunc(U u);
}

template<typename T>
template<typename U>
void MyClass<T>::myTemplatedFunc(U u) {}
// Class is:     template<typename T> MyClass<T>.
// Function is:  template<typename U> myTemplatedFunc(U u).

简而言之:这不是函数的模板参数列表,它是类的模板参数列表,用于使编译器可以将函数与类匹配,以便函数可以与类的模板参数相关联(例如将模板参数作为返回类型,或将其作为参数类型)。当函数的定义不包含在类的范围内时,这是必要的,因为函数本身不能在类的范围之外看到类的模板参数列表。

答案 2 :(得分:1)

您可能(也许应该)拥有一个非模板基类,该基类具有所有非模板类型相关的数据和方法。这样,不仅你的声明会更短(并且,对于某些编译器,甚至代码更短),你可以引用基类型并调用非模板类型相关的函数:MyClass<int> a(42); const MyBase& b = a; b.doSomethingUseless();