【问题标题】:How do I have specialization of template function in source file?如何在源文件中专门化模板函数?
【发布时间】:2020-03-20 18:49:18
【问题描述】:

我们在开发引擎时遇到了这个问题。我们想拥有

template <typename T>
std::pair<const uint8_t*, size_t> get_resource()
{
    return {nullptr, 0ull};
}

专门为许多Ts 服务。重要的部分是我们希望专业化存在于单独的源 (.cpp) 文件中并编译到我们引擎的静态库二进制文件中。将专业化放在源文件中至关重要,因为这些功能可能会被引擎的巨大代码库(至少几十万行)的其他标头频繁更改 #included。因此,如果它们存在于头文件中,则可能会在更改专业化定义之一时导致大部分项目的重建。对于这样的问题我找不到帮助,所以我在这里发布我们的解决方案。

【问题讨论】:

标签: c++ templates template-specialization specialization


【解决方案1】:

首先:将函数模板特化放在源文件中没有问题,因为 - 当特化时 - 它就像任何其他函数一样。棘手的是让来源#include带有模板定义的标头存在这种专门化。显然,在 c++ 中没有办法 declare 专业化。你可以做的是为一些T 强制实例化get_resource 模板(我们显然需要这样做,因为我们希望将特化编译成库二进制文件)。这可以使用以下语法来完成:

//force instantiation of get_resource for T=SOME_TYPE
template std::pair<const uint8_t*, size_t> get_resource<SOME_TYPE>();

但是:如果我们把它放在头文件中,就在模板定义之后,我们希望能够特化它,因为你不能特化已经实例化的东西。如果我们将它放在源文件中,在特化之后,源#includeing 带有模板定义的标头将无法看到它,因为它从未被声明为存在。这就是extern template 来救援的时刻。使用额外的extern 关键字强制实例化是一种声明,该模板函数将为某些给定的T(上面示例中的SOME_TYPE)实例化,但还没有。所以我们现在可以做的是使用这个extern关键字在头文件中声明强制实例化,然后在源文件中定义我们的特化和after来进行实际的强制实例化(没有extern)。这将确保特化对于来源#includeing 是可见的,同时它的定义可以放在源文件中(编译为单独的翻译单元)。

TL;DR

头文件

template <typename T>
std::pair<const uint8_t*, size_t> get_resource()
{
    return {nullptr, 0ull};
}

extern template std::pair<const uint8_t*, size_t> get_resource<SOME_TYPE>();

源文件

template<> std::pair<const uint8_t*, size_t> get_resource<SOME_TYPE>()
{
    return {reinterpret_cast<const uint8_t*>("whatever"), 9ull};
}

template std::pair<const uint8_t*, size_t> get_resource<SOME_TYPE>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    相关资源
    最近更新 更多