使用不同的默认模板参数和偏特化参数解析 class 模板

Resolution of class template with different default template argument and partial specialization argument

我有两个 class(结构)模板 AB,除了 第二个参数的默认参数 (在它们的主要模板中)和 模板特化的第二个参数 (在它们的部分特化中)在 A 相同(两者 void),而 B 中有所不同(分别为 voidint)。

#include <bits/stdc++.h>

/* primary class template A */
template <int N, class = void>
struct A : std::false_type {};

/* partial specialization of A */
template <int N>
struct A<N, std::enable_if_t<(N != 0), void>> : std::true_type {};

/* primary class template B */
template <int N, class = void>
struct B : std::false_type {};

/* partial specialization of B */
template <int N>
struct B<N, std::enable_if_t<(N != 0), int>> : std::true_type {};

int main() {

    std::cout << A<0>::value << std::endl; // 0 (i.e. A<0> extends std::false_type)
    std::cout << A<1>::value << std::endl; // 1 (i.e. A<1> extends std::true_type)

    std::cout << B<0>::value << std::endl; // 0 (i.e. B<0> extends std::false_type)
    std::cout << B<1>::value << std::endl; // 0 (i.e. B<1> extends std::false_type)

    return 0;
}

从输出中可以看出,B<1> 解析为主模板,而 A<1> 解析为部分专业化,我猜这是由于上述差异而发生的。这是相当违反直觉的,因为我预计会发生完全相反的情况。但是为什么会这样呢?编译器如何决定解析哪个版本,尤其是在这种情况下?

编辑: 正如@Enlinco 在他的 中正确识别的那样,我的困惑是由于期望在实例化 B<1> 时,编译器会解析“更专门用于 N != 0”的版本 B<N, int> , 更喜欢它而不是“更通用”的版本 B<N, void>.

如果我理解的混乱,当你看到

/* primary class template B */
template <int N, class = void>
struct B : std::false_type {};

/* partial specialization of B */
template <int N>
struct B<N, std::enable_if_t<(N != 0), int>> : std::true_type {};

你认为当编译器在main中看到B<1>时,

  • 看到通用模板没问题,
  • 然后就去看看专精和
    • 看到 (N != 0)true,
    • std::enable_if_t<(N != 0), int> 解析为 int
    • 因此导致 B<1, int>,这是一个很好的选择,因为它是一个专业。

故事略有不同。

template <int N, class = void>

只是意味着,正如评论中所建议的那样,当您编写 B<<i>an-int</i>> 时,编译器会看到 B<<i>an-int</i>, void>.

如果你从这个角度来看,你应该明白为什么不匹配会导致你观察到的行为:B<1> 只是 B<1, void>,没有专门针对它。