【发布时间】:2016-09-19 01:02:46
【问题描述】:
下面是一个简单的模板偏特化:
// #1
template <typename T, T n1, T n2>
struct foo {
static const char* scenario() {
return "#1 the base template";
}
};
// #2
// partial specialization where T is unknown and n1 == n2
template <typename T, T a>
struct foo<T, a, a> {
static const char* scenario() {
return "#2 partial specialization";
}
};
下面的主要在g++ (6.1) 和clang++ (3.8.0) 上得到不同的结果:
extern const char HELLO[] = "hello";
double d = 2.3;
int main() {
cout << foo<int, 1, 2> ::scenario() << endl;
cout << foo<int, 2, 2> ::scenario() << endl;
cout << foo<long, 3, 3> ::scenario() << endl;
cout << foo<double&, d, d> ::scenario() << endl;
cout << foo<double*, &d, &d> ::scenario() << endl;
cout << foo<double*, nullptr, nullptr> ::scenario() << endl;
cout << foo<int*, nullptr, nullptr> ::scenario() << endl;
cout << foo<nullptr_t, nullptr, nullptr> ::scenario() << endl;
cout << foo<const char*, HELLO, HELLO> ::scenario() << endl;
}
g++ 和 clang++ 的结果
<b>#</b> | <b>The code</b> | <b>g++ (6.1)</b> | <b>clang++ (3.8.0)</b> |1 | foo<int, 1, 2> | #1 as expected | #1 as expected |2 | foo<int, 2, 2> | #2 as expected | #2 as expected |3 | foo<long, 3, 3> | #2 as expected | #2 as expected |4 | foo<double&, d, d> | #1 -- why? | #2 as expected |5 | foo<double*, &d, &d> | #2 as expected | #2 as expected |6 | foo<double*, nullptr, nullptr> | #2 as expected | #1 -- why? |7 | foo<int*, nullptr, nullptr> | #2 as expected | #1 -- why? |8 | foo<nullptr_t, nullptr, nullptr> | #2 as expected | #1 -- why? |9 | foo<const char*, HELLO, HELLO> | #2 as expected | #2 as expected |
哪个是正确的?
代码:https://godbolt.org/z/4GfYqxKn3
编辑,2021 年 12 月:
自原始帖子以来的几年里,结果发生了变化,and were even identical for gcc and clang at a certain point in time,但再次检查,g++ (11.2) 和 clang++ (12.0.1) changed their results on references (case 4), but still differ on it。目前gcc 似乎一切正常,而clang 在参考案例中是错误的。
<b>#</b> | <b>The code</b> | <b>g++ (11.2)</b> | <b>clang++ (12.0.1)</b> |1 | foo<int, 1, 2> | #1 as expected | #1 as expected |2 | foo<int, 2, 2> | #2 as expected | #2 as expected |3 | foo<long, 3, 3> | #2 as expected | #2 as expected |4 | foo<double&, d, d> | #2 as expected | #1 -- why? |5 | foo<double*, &d, &d> | #2 as expected | #2 as expected |6 | foo<double*, nullptr, nullptr> | #2 as expected | #2 as expected |7 | foo<int*, nullptr, nullptr> | #2 as expected | #2 as expected |8 | foo<nullptr_t, nullptr, nullptr> | #2 as expected | #2 as expected |9 | foo<const char*, HELLO, HELLO> | #2 as expected | #2 as expected |
【问题讨论】:
-
@EissaN,请注意这是结构的特化,而不是函数。虽然我同意这确实是在怪癖区......
-
事实上,MSVC 产生了所有预期的结果。
-
EDG 在 C++14 严格模式下也会按预期选择部分特化。
-
我想补充一点,gcc 7.2 和 clang 4.0.0 分别是最早的版本,以提供所有预期的结果:godbolt.org/z/g6imAK
-
快进到 2020 年,
g++ 7.5.0和clang 8.0.0给出相同(正确)的结果
标签: c++ templates template-specialization partial-specialization