popular library的作者决定实施the following design pattern:
// my_traits.hpp
#include <stdio.h>
#include <assert.h>
template<typename T>
struct my_traits {
static bool equals(const T& x, const T& y) {
printf("base\n");
return x == y;
}
};
template<typename T>
void my_assert(const T& x, const T& y) {
assert(my_traits<T>::equals(x, y));
}
现在假设该库使用如下:
// main.cpp
void my_test1();
void my_test2();
int main() {
my_test1();
my_test2();
return 0;
}
和
// my_test1.cpp
#include "my_traits.hpp"
void my_test1() {
my_assert(-1.0, -1.0);
}
和
//my_test2.cpp
#include "my_traits.hpp"
#ifdef _WIN32
#include <float.h>
#define isnan _isnan
#else
#include <math.h>
#endif
template<>
struct my_traits<double> {
static bool equals(const double& x, const double& y) {
printf("specialization\n");
return x == y || isnan(x) && isnan(y);
}
};
void my_test2() {
my_assert(-1.0, -1.0);
}
现在,
$ g++ main.cpp my_test1.cpp my_test2.cpp && ./a.out
base
base
,而
$ g++ main.cpp my_test2.cpp my_test1.cpp && ./a.out
specialization
specialization
当然,无论链接顺序如何,图书馆的用户都希望获得以下结果:
base
specialization
没有专门化或重载(内联)my_assert
而不是my_traits
,并且知道在包含my_traits.hpp
的每个翻译单元中注入相同的专业化是不可接受的(或可维护的) ,任何人都可以想到在不修改my_traits.hpp
或专门化my_assert
(或使用double
:)的kludgy包装类的情况下实现理想行为的另一种技巧吗?
答案 0 :(得分:5)
§14.7.3[temp.expl.spec] / p6(强调补充):
如果是模板,成员模板或类模板的成员 明确专门然后应宣布专业化 在第一次使用该特化之前会导致一个 隐式实例化发生在每个翻译单元中 发生了这种用途;无需诊断。如果是程序 没有为显式专业化提供定义 专业化的使用方式会导致 隐式实例化发生或成员是虚拟成员 功能,程序格式错误,无需诊断。