为另一个模板类型声明模板专门化的正确方法是什么?

时间:2010-04-28 02:10:07

标签: c++ templates

模板函数专业化的通常定义是这样的:

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的特化,但我无法分辨编译器是否正在看到它,或者它是否认为它是它的重载或其他东西。

4 个答案:

答案 0 :(得分:4)

您的解决方案不是模板特化,而是std命名空间中函数的重载,根据c ++标准是“未定义的行为”。

This question正是您的问题。

Scott Meyers在Effective C ++中对此进行了讨论,usenet's comp.lang.c++上有一个后续主题。

  • 他建议您在固定的名称空间中定义它。
  • 确保'fixed'在命名空间中。
  • 不要使用'std ::'作为交换前缀调用。
  • Koenig (a.k.a. argument dependent) lookup找到合适的交换功能。

如果在尝试在命名空间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