部分模板专业化类型折叠规则

时间:2017-09-24 22:27:10

标签: c++ templates partial-specialization

抱歉缺少更好的头衔。

在尝试实现我自己的std::move版本并理解它有多容易时,我仍然对C ++如何处理部分模板特化感到困惑。我知道它们是如何工作的,但我发现这种规则很奇怪,我想知道其背后的原因。

template <typename T>
struct BaseType {
    using Type = T;
};

template <typename T>
struct BaseType<T *> {
    using Type = T;
};

template <typename T>
struct BaseType<T &> {
    using Type = T;
};

using int_ptr = int *;
using int_ref = int &;

// A and B are now both of type int
BaseType<int_ptr>::Type A = 5;
BaseType<int_ref>::Type B = 5;

如果没有RemoveReference的部分专精,T总是T:如果我给了int &,它仍然是int & 1}}贯穿整个模板。

但是,部分专用模板似乎会折叠引用和指针:如果我提供了int &int *,并且这些类型与专用模板中的类型匹配,T只会是int

这个功能非常棒,非常有用,但我很好奇,我想知道这个不太明显的怪癖背后的官方推理/规则。

2 个答案:

答案 0 :(得分:1)

如果您的模板模式与T&匹配到int&,则T&int&,这意味着Tint

特化中的类型T仅与主模板中的T相关,因为它用于模式匹配第一个参数。

在专业化中将T替换为XU可能会让您更加困惑。重用变量名称可能会造成混淆。

template <typename T>
struct RemoveReference {
  using Type = T;
};

template <typename X>
struct RemoveReference<X &> {
  using Type = X;
};

X&匹配T。如果X&TTint&,则Xint

为什么标准会说这个?

假设我们看一下不同的模板专业化:

template<class T>
struct Bob;

template<class E, class A>
struct Bob<std::vector<E,A>>{
  // what should E and A be here?
};

答案 1 :(得分:0)

部分特化与函数模板非常相似:实际上,重载函数模板经常被误认为是它们的部分特化(这是不允许的)。给定

template<class T>
void value_assign(T *t) { *t=T(); }

然后显然T必须是没有(最外层)指针状态的参数类型的版本,因为我们需要该类型来计算通过指针分配的值。我们当然不会写value_assign<int>(&i);来调用这种类型的函数,因为可以推导出参数。

在这种情况下:

template<class T,class U>
void accept_pair(std::pair<T,U>);

请注意,模板参数的数量大于的数量<#34;提供的&#34;作为输入(即,用于扣除的参数类型的数量):复杂的类型可以提供多种类型的价值&#34;信息。

所有这些看起来与类模板非常不同,其中类型必须明确给出(仅sometimes true as of C++17)并且它们在模板中逐字使用(如您所说)。< / p>

但请再次考虑部分专业化:

template<class>
struct A;                               // undefined
template<class T>
struct A<T*> { /* ... */ };             // #1
template<class T,class U>
struct A<std::pair<T,U>> { /* ... */ }; // #2

这些分别与(不相关的)函数模板value_assignaccept_pair完全同构。例如,我们必须编写A<int*>来使用#1;但这简直类似于调用value_assign(&i):特别是,模板参数仍然推导,只是这次来自显式指定的类型int*而不是类型表达式&i。 (因为即使提供显式模板参数也需要推断,部分特化必须支持推导其模板参数。)

#2再次说明了在此过程中不保留类型数量的想法:这应该有助于打破错误的印象,即&#34; 模板参数&#34;应继续参考&#34; 提供的类型&#34;。因此,部分特化不仅仅声称一组(通常是无界的)模板参数:它们解释它们。

又一个相似之处:同一类模板的多个部分特化之间的选择是exactly the same,因为它们在重载时丢弃不太具体的函数模板。 (但是,由于在部分特化情况下不会发生重载解析,因此该过程必须除去那里的所有候选者。)