我应该声明我的函数模板专业化还是定义它们就足够了
Should I declare my function template specializations or is defining them enough?
我有一些类可以检查。实现这一点的代码在头文件中声明了一个函数模板,并将其专门用于不同的源文件:
// check.h
template <class T>
bool check(const T& object);
// class1.h
struct Class1 {int mass;};
// check_class1.cpp
#include "class1.h"
#include "check.h"
template <>
bool check(const Class1& object) {return object.mass < 100;}
// class2.h
struct Class2 {int price;};
// check_class2.cpp
#include "class2.h"
#include "check.h"
template <>
bool check(const Class2& object) {return object.price < 1000;}
// class3.h
struct Class3 {int x;};
... // 10 more classes which I can check
这个代码是这样使用的:
#include "class1.h"
#include "class2.h"
#include "class3.h"
#include "check.h"
int main()
{
Class1 object1{50};
Class2 object2{500};
Class3 object3{8};
check(object1); // OK
check(object2); // OK
check(object3); // a link error appears here
}
这个效果很好。当我添加另一个可以检查的类Class3
时,我不需要触摸头文件,因为它定义了一个非常宽的接口。如果我忘记为Class3
实现check
函数,链接器将用错误消息提醒我。
我的问题是:这种行为是有保证的,还是我的代码靠运气工作?我正在使用Visual Studio。
如果我想专门化我的函数模板,我不应该在头文件中声明我的所有专门化吗?
为了安全起见,我会添加这些声明(好吧,假设我不会因为任何原因而重载(。我认为法律对此不太明确。首先,我们有
[温度解释规范]
6如果模板、成员模板或类的成员模板是明确专门化的,那么专门化应该是在第一次使用将导致在发生这样的使用;不需要进行诊断。如果程序没有为明确的专业化提供定义,并且或者专用化的使用方式会导致要进行的隐式实例化或成员是虚拟成员功能,程序格式错误,无需诊断。一从不为显式生成隐式实例化已声明但未定义的专门化。
如果我读得正确,这意味着如果向main.cpp
添加了显式专用化,那么它必须出现在main
之前。因为这就是可能发生隐式实例化的地方。这段话并没有让你的代码变成格式错误的NDR,因为用法和明确的专业化出现在不同的TU中。但它确实引起了人们的担忧。
另一方面,有这样一段话:
[temp]
7一种函数模板、类模板的成员函数,类模板的变量模板或静态数据成员定义在每个隐含的翻译单元中实例化,除非显式指定相应的专门化在某个翻译单元中实例化;不需要进行诊断。
这个允许我们在单独的看不见的TU中显式地实例化。但它并没有为明确的专业化提供津贴。我不能说这是故意的还是疏忽。
它之所以有效,很可能是因为整个事情是如何实现的。当函数声明被隐式实例化时,它会生成一个恰好与显式专门化生成的符号匹配的符号。匹配的符号意味着一个愉快的链接器,所以一切都会构建和运行。
但从语言律师的角度来看,我认为我们可以将这里的行为称为不作为。它是未定义的,只是因为标准没有解决它。所以回到我的开场白,为了安全起见,我会添加它们,因为至少这样的位置是由标准解决的。
您必须在使用每个显式专用化之前声明它们。但是,您可以在声明其专用类型的标头中执行此操作。
// class2.h
struct Class2 {int price;};
template <class T>
bool check(const T& object);
template <>
bool check(const Class2& object)
(我仍然不明白为什么使用重载不是一种选择(。
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- std::带有自定义缓冲区的 iostream 不允许我写入
- 我的超类中的模板问题与结构定义
- 查找定义我的 C/C++ 函数/宏的文件比'grep'更简单的方法
- 我的自定义使用 std::unordered_map 的性能非常慢
- 为什么我的C++代码无法编译,出现未定义的引用错误
- 我的类中几乎所有的构造函数和解构函数都被隐式定义为已删除?
- 我的代码中C++未定义的引用错误?
- 我无法让我的程序工作,我一直得到未定义的符号:C
- 在C++中,我可以在定义自己的复制构造函数后跳过定义赋值运算符吗?
- Metatrader 5 向导无法识别我的自定义交易信号模块
- 我应该声明我的函数模板专业化还是定义它们就足够了
- (C++)我的自定义数组无法初始化(编译错误)
- 使用Cygwin C++时出现未定义的引用错误,为什么我的文件没有链接?
- 如果我想从类型"T"定义元素的容器(来自 STL),那么"T"必须使用默认构造函数?
- 如何在我的类unique_ptr中提供自定义删除器?
- 为什么我的代码不适用于自定义分配器?
- 是否需要定义我的退货类型
- 我应该总是在头文件中定义我的整个模板类吗
- 多个符号定义,但我只定义我的符号一次