跳转至

最后更新:2026-10-13

C++ 类模板优于函数模板

https://stackoverflow.com/questions/5688355/partial-specialisation-of-member-function-with-non-type-parameter

最近看到一个很有意思的模版问题,看看大家对函数模版与类模版的基础掌握的如何,对于下面这个例子会出现什么问题?

你一般使用什么方法进行修复?

template <typename T, int R>
struct foo {
  foo(const T& v) : value_(v) {}

  void bar() {
    std::cout << "Generic" << std::endl;
    for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
  }

  T value_;
};

template <>
void foo<float, 3>::bar() {
  std::cout << "Float" << std::endl;
  for (int i = 0; i < 3; ++i) std::cout << value_ << std::endl;
}

template <int R>
void foo<double, R>::bar() {
  std::cout << "Double" << std::endl;
  for (int i = 0; i < R; ++i) std::cout << value_ << std::endl;
}

答案是:最后两个特化直接编译不过。

(1)第一个 template <> void foo<float, 3>::bar() 是**全特化**,没问题;

(2)第二个 template <int R> void foo<double, R>::bar() 想做**偏特化**——但函数模板不允许偏特化!编译器把它当成一个新的函数模板重载来解析,签名又对不上,直接报错。

怎么修?类模板登场

C++ 的规则是:函数模板只能全特化,不能偏特化;类模板两者都行。所以惯用法是把"需要按类型分支的逻辑"从函数模板里抽出来,放进一个类模板(通常就是 trait/policy),对类做偏特化:

template <typename T, int R>
struct bar_impl {
  static void run(foo<T, R>& f) {
    std::cout << "Generic" << std::endl;
    for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
  }
};

template <int R>
struct bar_impl<double, R> {  // 类模板偏特化:合法!
  static void run(foo<double, R>& f) {
    std::cout << "Double" << std::endl;
    for (int i = 0; i < R; ++i) std::cout << f.value_ << std::endl;
  }
};

template <typename T, int R>
void foo<T, R>::bar() { bar_impl<T, R>::run(*this); }

这也是 STL 的标准操作:iterator_traits、__type_traits 全都是"类模板承载偏特化"的路数。

小结

(1)函数模板:只能重载 + 全特化,不能偏特化;

(2)需要"对某类类型做特殊实现"时,把实现搬进类模板,用偏特化/trait 分发;

(3)C++11 之后很多场景还能用 if constexpr 直接在函数体里分支,连类模板都省了——但它和偏特化的取舍,留给你思考。

相关主题

评论