为什么我可以部分专业化但不能完全专门化C ++中的成员模板?

时间:2018-06-07 00:30:47

标签: c++ templates template-specialization partial-specialization rationale

IMO,C ++模板规则似乎限制太多,并且定义了编译器实现。但在这里,我有一个特定的行为,我很难缠头。

在下面的问题中,我有意识地避免明确地专门化父类。

问题是,我可以部分专门化一个成员,但不能完全专门化。这实际上是反直觉的,因为您可以轻松地将虚拟模板添加到完全专用的模板中并使其部分专用。这是怎么回事?

重要编辑:这很重要,因为,正如我们所知,你不能专门化成员函数而不专门化这个类(可以看作是这个问题的组合,需要部分专业化,以及c ++这一事实)不允许部分专门的功能。我不知道这些是否相关,但至少它们是一致的),因此如果你想在你的班级中使用一个你可以专注的功能,你就会被使用仿函数所困扰。最重要的是,你需要添加一个虚拟模板参数,以使其工作!!

这有效:

template <class T>
class A
{
  template<typename Y, typename Z>
  struct C{
      void operator()(int x);
  };

  template<typename Z>
  struct C<int, Z>{
      void operator()(int x);
  };
};

template <class T>
template <typename Z>
void A<T>::C<int, Z>::operator()(int x){

}

但这不是:

template <class T>
class A
{
  template<typename Y>
  struct C{
      void operator()(int x);
  };

  template<>
  struct C<int>{
      void operator()(int x);
  };
};

template <class T>
template <>
void A<T>::C<int>::operator()(int x){

}

编辑:Sean F.在评论中指出,编译器很难选择专业化。但问题在于,部分专业化不会使问题消失。所以这不是答案。

1 个答案:

答案 0 :(得分:3)

作为一般规则,模板函数专业化是一个坏主意。使用重载或标签分派。例如:

template<class T>struct tag_t{};

template<class T>
auto foo(T& t){ return foo( tag_t<T>{}, t ); }

现在我们可以使用重载来分派:

void foo( tag_t<int>, int& i ){ i+=3; }
template<class T>
void foo( tag_t<T>, T& t ){ t*=2; }

这里没有专业化。我们使用重载解析规则来选择实现。这对成员来说很好。

我们只对顶级课程使用专业化。即使在那里,我经常试图通过标签分派和使用decltype来选择实现,因为重载分辨率通常会提供更好的模式匹配。

如果您确实需要一个成员类,请将您的成员类替换为顶级类和一些朋友声明。

template<class T, class Y>
struct A_C;
template <class T>
class A
{
  template<class T0, class Y0>
  friend class A_C<T0, Y0>;
  template<class Y>
  using C=A_C<T,Y>;
};
template<class T, class Y>
struct A_C {
  // implementation of A::C
};

现在你对A_C的专业化非常不受限制了。没有你的问题。