【问题标题】:Why can I partially specialize but can't fully specialize member templates in C++?为什么我可以部分专门化但不能完全专门化 C++ 中的成员模板?
【发布时间】:2018-11-16 18:56:34
【问题描述】:

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){

}

编辑:cmets 中的 Sean F. 指出编译器很难选择专业化。但这里的问题是,部分专业化并不能解决这个问题。所以这不可能是答案。

【问题讨论】:

  • 你已经正确地陈述了规则(C++17 temp.expl.spec/16 "[...] 如果它的封闭类模板不是,则声明不应显式特化类成员模板也明确专门化”)。我不知道原因,希望有人知道!
  • 谢谢,我通过实验得出了结论。因此,知道这是事实可以减轻一定程度的不确定性。

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


【解决方案1】:

一般来说,模板函数特化是个坏主意。使用重载或标签调度。例如:

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 的完全不受限制的专业化。没有你的问题。

【讨论】:

  • 好的,感谢您提供替代方法。但我也可以使用 'if constexpr (std::is_same::value)' 来模拟相同的行为。一个问题似乎是,即使新的语言特性实际上允许某种行为,旧标准仍然存在。为什么不允许这样做并让我们能够将大量 if constexpr - else 语句分解为单独的函数?
  • @A__A 我给了你一种方法,可以将巨大的 if constexpr else 语句分解成单独的函数;您似乎想使用模板专业化来做到这一点,这是一个非常不同的要求。专门化函数是个坏主意,它的工作原理非常违反直觉;我猜想是否不包括今天添加的模板函数专业化。在 9999/10000 情况下,覆盖更清洁、更好。使函数的专业化更容易有一个微小的好处,并且可能会导致人们在不应该这样做的时候这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多