1

我有一个带有模板参数 T 的类 A,它仅限于两种类型:T1 和 T2。因此,我为类型 T1 和 T2 显式实例化了类 A,这样 A 的功能可以在源文件中定义,并且不需要在每次包含 A.hpp 时都重新编译。

A.hpp:

template<typename T>
class A {
public:
    void basicMethod();
};

template class A<T1>;
template class A<T2>;

A.cpp:

template<typename T>
void A<T>::basicMethod() {
    // ...
}

但是,现在我想向 A<T1> 和 A<T2> 添加一个模板化方法,其中模板参数再次被限制为两种类型:S1 和 S2:

A.hpp:

template<typename T>
class A {
public:
    void basicMethod();
    template<typename S>
    void advancedMethod();
};

template class A<T1>;
template class A<T2>;

// How to explicitly instantiate A::advancedMethod here?

A.cpp:

template<typename T>
void A<T>::basicMethod() {
    // ...
}

template<typename T>
template<typename S>
void A<T>::advancedMethod() {
    // ...
}

如何为 (T, S) = {T1, T2} x {S1, S2} 显式实例化 A<T>::advancedMethod<S>?根据我在网上找到的内容,我尝试将这样的内容添加到 A.hpp 的末尾:

template void A<T1>::advancedMethod(S1);
template void A<T1>::advancedMethod(S2);
template void A<T2>::advancedMethod(S1);
template void A<T2>::advancedMethod(S2);

但是,这根本不起作用。

4

1 回答 1

3

类模板的成员函数模板的显式实例化定义

你几乎明白了。正确的语法是:

template void A<T1>::advancedMethod<S1>();
template void A<T1>::advancedMethod<S2>();
template void A<T2>::advancedMethod<S1>();
template void A<T2>::advancedMethod<S2>();

特别注意,这advancedMethod()是一个在单个类型模板参数上参数化的函数模板,没有函数参数:您对函数模板的不同特化(对于定义它的类模板的不同特化)的显式实例化定义应该像显式类模板的实例化定义,提供模板参数 ( <...>) 以指定您希望显式实例化的特化。

最后,对于advancedMethod()显式实例化的每个特化,自然需要定义函数模板(通过主模板定义或显式特化);特别是(cppreference):

如果使用显式实例化定义显式实例化类模板的函数模板、变量模板、成员函数模板或成员函数或静态数据成员,则模板定义必须存在于同一翻译单元中。


将模板函数(/类模板成员函数)的定义与其声明分开:-timl.hpp模式

作为上述要求的结果,在提供显式实例化定义时,您通常将它们放在相关模板化实体的定义之后,在源文件中,其中典型的用例是模板化实体的公共 API 的用户应该无权访问定义(如您的示例中所示)。这是必不可少的,因为根据[temp.spec]/5 ,您可能不会在不同的翻译单元上显式地两次实例化相同的专业化:

对于给定的一组模板参数,

  • 一个显式的实例化定义在程序中最多出现一次
  • [...]

诊断违反此规则的情况不需要实现。

因此,如果您将显式实例化放在头文件中,然后将头文件包含在多个源文件中,那么您的程序将是格式错误的 NDR。

// a.hpp
template<typename T>
class A {
public:
    void basicMethod();
    template<typename S>
    void advancedMethod();
};

// a-timpl.hpp
#include "a.hpp"

template<typename T>
void A<T>::basicMethod() {
    // ...
}

template<typename T>
template<typename S>
void A<T>::advancedMethod() {
    // ...
}

// a.cpp
#include "a-timpl.hpp"
#include "t1.hpp"
#include "t2.hpp"
#include "s1.hpp"
#include "s2.hpp"

// Explicit instantiation definitions for
// production intent.
template class A<T1>;
template class A<T2>;

template void A<T1>::advancedMethod<S1>();
template void A<T1>::advancedMethod<S2>();
template void A<T2>::advancedMethod<S1>();
template void A<T2>::advancedMethod<S2>();

对于测试,您同样包含-timpl.hpp头文件而不是主头(主头用于公共 API 公开),以便您可以使用模板定义来显式实例化测试中使用的特化:

// a_test.cpp
#include "a-timpl.hpp"
#include "t1_mock.h"
#include "t2_mock.h"
#include "s1_mock.h"
#include "s2_mock.h"

// Explicit instantiation definitions for
// test intent.
template class A<T1Mock>;
template class A<T2Mock>;

template void A<T1Mock>::advancedMethod<S1Mock>();
template void A<T1Mock>::advancedMethod<S2Mock>();
template void A<T2Mock>::advancedMethod<S1Mock>();
template void A<T2Mock>::advancedMethod<S2Mock>();
于 2020-11-19T11:09:38.180 回答