使用不同的默认模板参数和偏特化参数解析 class 模板
Resolution of class template with different default template argument and partial specialization argument
我有两个 class(结构)模板 A
和 B
,除了 第二个参数的默认参数 (在它们的主要模板中)和 模板特化的第二个参数 (在它们的部分特化中)在 A
中 相同(两者 void
),而 在 B
中有所不同(分别为 void
和 int
)。
#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>
,没有专门针对它。
我有两个 class(结构)模板 A
和 B
,除了 第二个参数的默认参数 (在它们的主要模板中)和 模板特化的第二个参数 (在它们的部分特化中)在 A
中 相同(两者 void
),而 在 B
中有所不同(分别为 void
和 int
)。
#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>
,没有专门针对它。