1

我发现自己对模板的理解存在挑战,我知道模板的源代码必须放在头文件中才能访问模板实例化的所有依赖类型。

所以,在这个例子中:

// This code cannot be placed in the cpp file
template <typename T> T foo(T v)
{
    return -v;
}

的主体T foo(T v)必须放在头文件中,然后,当foo函数在某处实例化时,会创建“真实”主体函数,T用真实类型替换符号。使用此代码:

int bar = 5;
float baz = 6.66f;
bar = foo<int>(bar);
baz = foo<float>(baz);

模板实例化机制基于之前定义的模板创建以下函数:

int foo(int v)
{
    return -v;
}

float foo(float v)
{
    return -v;
}

但是,当我们有一个模板类时,该类可以具有根本不使用依赖类型的函数:

template <typename T> class Foo
{
    Foo() : mistery(0), value(0) {}; // We're using the dependant type.
    AddMistery() { ++mistery; }; // We are not using the dependant type.

    int mistery;
    T value;
};

我首先想到该AddMistery方法可以放在cpp文件中,因为该方法没有使用依赖类型,但是当我尝试时,链接失败。这会儿我一记耳光,想起模板类的不同实例不是同一个类。因此,当链接器完成它的工作时,它会查找AddMistery方法的主体,但没有找到它,因为 ir 被放入 cpp 文件中:

// Foo.h
template <typename T> class Foo
{
    Foo() : mistery(0), value(0) {}; // We're using the dependant type.
    AddMistery(); // We are not using the dependant type.

    int mistery;
    T value;
};

// Foo.cpp
#include "Foo.h"

template <typename T> Foo<T>::AddMistery()
{
    ++mistery;
}

// Main.cpp
#include "Foo.h"

int main(int argc, char **argv)
{
    Foo<int> i;
    Foo<float> f;

    i.AddMistery(); // Link Error, where's the Foo<int>::AddMistery body?
    f.AddMistery(); // Link Error, where's the Foo<float>::AddMistery body?

    return 0;
};

所以,最后,这是一个问题:有一种方法可以在头文件和 cpp 文件之间拆分模板类,将所有非类型相关方法的主体移动到 cpp,而不是将所有方法主体保留在头文件中?

4

2 回答 2

1

除非您打算将模板仅用于有限的知名类型集,例如和int,否则这是不可能的。在这种情况下,您可以使用显式实例化并将模板函数定义放在文件中。shortdouble.cpp

于 2012-08-31T11:12:29.423 回答
1

简短的回答是否定的,因为类模板不是类,除非您使用某个模板参数对其进行实例化。所以没有Foo::AddMystery()实施。

可以这样想:成员函数知道依赖类型,因为它们有一个隐式的第一个参数,它是指向它们类的对象的指针。所以

Foo<int> f;
f.AddMistery();

相当于

Foo<int> f;
Foo<int>::AddMistery(&f);

如果您有某些类型的模板的实例化,那么您可以Foo<int>::AddMistery在文件中实现.cpp,但这与不需要模板参数在其主体中的函数无关。

于 2012-08-31T11:03:02.373 回答