为什么在实现所有模板化类方法之前需要'template <class t =“”>

时间:2018-12-03 14:44:18

标签: c++ templates

如果我们有一个标准班级:

class Foo {
  public:
    int fooVar = 10;
    int getFooVar();
}

getFooVar()的实现为:

   int Foo::getFooVar() {
       return fooVar;
   }

但是在模板化类中:

template <class T>
class Bar {
  public:
    int barVar = 10;
    int getBarVar();
}

getBarVar()的实现必须是:

template <class T>
int Bar<T>::getBarVar(){
   return barVar();
}

考虑到函数未使用的事实,为什么在template <class T>getBarVar的函数实现之前必须有Bar<T>::行(与Bar ::相对)任何模板变量?

5 个答案:

答案 0 :(得分:6)

您需要它,因为Bar不是一个类,它是一个模板Bar<T>是课程。

答案 1 :(得分:3)

正如其他答案所说,

Bar本身是模板。

但是现在让我们假设您不需要它,毕竟,您指定了它,然后我添加了另一个模板参数:

template<typename T1, typename T2>
class Bar
{
    void something();
};

为什么:

template<typename T1, typename T2>
void Bar<T1, T2>::something(){}

不是:

void Bar::something(){}

如果您想专门针对一种类型T1而不是另一种类型的实现,将会发生什么?您将需要添加该信息。这就是该template声明起作用的地方,以及为什么您还需要在常规实现(IMHO)中使用它。

template<typename T>
void Bar<T, int>::something(){}

答案 2 :(得分:1)

实例化该类时,编译器将检查实现是否存在。但是在编写代码时,最终类型(即实例化类型)尚不清楚。

因此,编译器会为您实例化定义,如果编译器应实例化某些内容,则需要对其进行模板化。

答案 3 :(得分:0)

对此问题的任何回答都归结为“因为该标准如此规定”。但是,让我们检查一下禁止(因为这些错误有助于我们理解该语言的期望),而不是背诵标准语言。 “单个模板”情况很快就用完了,因此,请考虑以下内容:

template<class T>
class A
{
    template<class X>
    void foo(X);
};

也许我们可以对两者都使用一个模板参数?

template<class U>
void A<U>::foo(U u)
{
    return;
}
error: out-of-line definition of 'foo' does not match any declaration in 'A<T>'

不,我们不能。好吧,也许是这样?

template<class U>
void A<U>::foo<U>(U u)
{
    return;
}
error: cannot specialize a member of an unspecialized template

不。这吗?

template<class U, class V>
void A<U>::foo(V u)
{
    return;
}
error: too many template parameters in template redeclaration

如何使用默认值模拟匹配?

template<class U>
template<class V = U>
void A<U>::foo(V u)
{
    return;
}
error: cannot add a default template argument to the definition of a member of a class template

很明显,编译器担心匹配声明。这是因为编译器不将模板定义与特定的调用(就像从一种功能语言使用的那样)进行匹配,而是将其与模板声明进行匹配。 (到目前为止的代码here)。

因此,在基本级别上,答案是“因为模板定义必须与模板声明匹配”。这仍然留下了一个问题:“为什么我们不能只省略类模板参数呢?” (据我所知模板没有模棱两可的地方,所以重复模板参数无济于事)

答案 4 :(得分:0)

考虑功能模板声明

tempalte <typename T> 
void foo();

现在是一个定义

void foo() { std::cout << "Hello World"; }

是以上模板的特化或过载。您必须选择两者之一。例如

#include <iostream>

template <typename T>
void foo();

void foo() { std::cout << "overload\n"; }

template <typename T>
void foo() { std::cout << "specialization\n"; }

int main() {
    foo();
    foo<int>();
}

打印:

overload
specialization

您的问题的简短答案是:规则是这样的,尽管如果您可以从模板的定义中省略template <typename T>,则将需要另一种方式来定义重载。