模板函数专业化的通常定义是这样的:
class Foo {
[...]
};
namespace std {
template<>
void swap(Foo& left, Foo& right) {
[...]
}
} // namespace std
但是,如果专业化的类型本身就是模板,那么如何正确定义专业化呢?这就是我所拥有的:
template <size_t Bits>
class fixed {
[...]
};
namespace std {
template<size_t Bits>
void swap(fixed<Bits>& left, fixed<Bits>& right) {
[...]
}
} // namespace std
这是宣布swap
的正确方法吗?它应该是模板函数std::swap
的特化,但我无法分辨编译器是否正在看到它,或者它是否认为它是它的重载或其他东西。
答案 0 :(得分:4)
您的解决方案不是模板特化,而是std命名空间中函数的重载,根据c ++标准是“未定义的行为”。
This question正是您的问题。
Scott Meyers在Effective C ++中对此进行了讨论,usenet's comp.lang.c++上有一个后续主题。
如果在尝试在命名空间std中定义此错误时看到编译错误,则可能是由于您不幸选择了类名:)在namespace std
内,“fixed”被视为std::fixed
,浮点精度算子。
答案 1 :(得分:3)
不允许使用函数模板的部分特化,因此fixed<Bits>
的模板声明了一个新的重载,而不是一个特殊化。
这并不重要,因为像std::swap(a, b)
这样的调用只会选择最佳匹配函数。它不要求该函数是通用std::swap
模板的特化。如果最佳匹配函数是重载而不是特化,则将调用重载。
答案 2 :(得分:2)
从语法上讲,您的“专业化”正确完成。然而,正如其他人已经指出的那样,它并不是真正的部分专业化,而是功能过载。函数模板不支持部分特化。
值得注意的是,语言规范禁止向命名空间std
添加任何内容(参见17.4.3.1/1)。我明白为什么你坚持在std
专门做这件事,因为你试图对std::swap
进行部分专业化。由于您的swap
实际上是一个重载而非专业化,因此您可以在std
之外,在包含yor fixed
的同一命名空间内安全地执行此操作。依赖于参数的名称查找(“Koenig查找”)应确保在应用于swap
类型的参数时,通过名称查找找到fixed
(除非调用代码明确引用std::swap
而不只是swap
)。
答案 3 :(得分:-4)
无法使用在运行时之前未确定的值声明模板参数。要使用数字作为模板参数,它必须是'const'才能在编译时解析:
template <const size_t Bits>
class fixed {
[...]
};
namespace std {
template<const size_t Bits>
void swap(fixed<Bits>& left, fixed<Bits>& right) {
[...]
}
} // namespace std