函数模板:外部模板与显式专用化
Function templates: extern template vs explicit specialisation
请考虑以下函数模板声明:
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);
此模板只有一个可能的有效实例化,即T = int
.我想把这个定义放在一个实现文件中。我可以想到两种可能的方法。(如果你想知道为什么我会这样做,而不仅仅是说void foo(int i)
,这是因为模板版本阻止了调用站点的隐式转换。
方法1:
我可以使用extern template
声明来告诉其他 TU,foo<int>()
已在其他地方实例化:
// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);
extern template void foo(int);
// In foo.cpp
template <typename T, typename>
void foo(T i) { ... } // full template definition
template void foo(int); // explicit instantiation with T = int
方法2:
我可以为int
案例提供明确的专业化:
// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);
template <> void foo(int i); // explicit specialisation declaration (*)
// In foo.cpp
template <>
void foo(int i) { ... } // explicit specialisation definition
问题:
- 这两种方法都是合法的,还是我无意中依赖 UB?
- 如果两者都是合法的,除了方法2的打字性略少之外,是否有充分的理由偏爱一种方法而不是另一种方法?GCC 和 Clang 在这两种方法中都同样有效。
- 对于方法 2,是否确实需要明确的专业化声明
(*)
?同样,如果省略它,GCC 和 Clang 都非常高兴,但这样做让我感到不舒服,因为在另一个 TU 中调用foo(3)
是一个模板的隐式实例化,没有可见的定义,也没有承诺这样的定义存在于其他地方。
还有第三种方法。 在方法 3 中,指定要拥有的函数,并添加模板重载并将其标记为delete
。 那看起来像
void foo(int i)
{
// stuff
}
template <typename T>
void foo(T t) = delete;
由于模板版本将完全匹配所有类型,因此在除int
以外的所有情况下都将首选,因为非模板完全匹配优于模板版本。 因此,您只能使用int
调用foo
,而所有其他类型都会给您一个错误,指出他们正在尝试调用已删除的函数void foo(T t)
。
现场示例
相关文章:
- .cpp和.h文件中的模板专用化声明
- 调用专用模板时出错"no matching function for call to [...]"
- 模板专用化(按容器):value_type
- 在函数内部的声明中初始化数组,并在外部使用它
- 使外部项目可用于find_package CMake
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 使用外部SDK工具链文件在VisualStudio上生成项目编译错误
- C++:来自外部文件的Trivia
- 从函数角度看ID到文件路径的内部与外部映射
- C++:将外部库链接到dll库
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 节俭并发:未解决的外部问题
- 如何在c++中从git建立外部库
- 未解析的外部符号_MsiLocateComponentW@12.
- 如何使用对C函数和类对象的外部调用来处理C++头文件
- 函数模板:外部模板与显式专用化
- 从类外部访问专用虚拟函数
- const QString&的显式模板专用化导致未解析的外部
- 全局变量外部声明后的线程专用指令
- 错误 LNK2019: 未解析的外部符号"__declspec(DLL导入) 专用