我应该声明我的函数模板专业化还是定义它们就足够了?

Should I declare my function template specializations or is defining them enough?

我有一些 class 可以检查。实现它的代码在头文件中声明了一个函数模板,并将其专门用于不同的源文件:

// 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
}

这很好用。当我添加另一个我可以检查的 class Class3 时,我不需要触及头文件,因为它定义了一个非常广泛的接口。如果我忘记为 Class3 实现 check 函数,链接器会用错误消息提醒我。

我的问题是:这种行为是有保证的,还是我的代码能正常工作?我正在使用 Visual Studio.

如果我想特化我的函数模板,我不应该在头文件中声明我所有的特化吗?

您必须在使用之前声明每个显式特化。但是您可以在 headers 中声明它专门针对的类型。

// class2.h
struct Class2 {int price;};
template <class T>
bool check(const T& object);
template <>
bool check(const Class2& object)

(我仍然不明白为什么不能使用重载)。

为了安全起见,我会添加这些声明(好吧,假设我没有因为任何原因而超载)。我认为法律对此并不太明确。首先,我们有

[temp.expl.spec]

6 If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.

如果我没看错的话,这意味着如果向 main.cpp 添加显式特化,则它必须出现在 main 之前。因为那是可能发生隐式实例化的地方。该段落不会使您的代码完全消除格式错误的 NDR,因为用法和显式专业化出现在不同的 TU 中。但这确实引起了关注。

另一方面,有这一段:

[temp]

7 A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated unless the corresponding specialization is explicitly instantiated in some translation unit; no diagnostic is required.

这个允许我们在单独的看不见的 TU 中明确地实例化。但它没有为明确的专业化提供津贴。不知道是有意还是无意。

它起作用的原因可能是由于整个事情的实施方式。当函数声明被隐式实例化时,它会产生一个恰好与显式特化产生的符号相匹配的符号。匹配的符号意味着一个快乐的链接器,所以一切都可以构建和运行。

但从语言律师的角度来看,我认为我们可以将此处的行为称为未定义遗漏。它未定义仅仅是因为标准没有解决它。因此,回到我的开场白,为了安全起见,我会添加它们,因为至少这样放置是由标准解决的。