// #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;
}
# | The code | g++ (6.1) | clang++ (3.8.0) |
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 |
答案 0 :(得分:1)
我认为clang nullptr
更像是in-build变量,就像in-build类型int
一样。 nullptr
实际上没有类型。 nullptr_t
的声明(没有定义)是struct nullptr_t nullptr_t;
。对于问题的答案是正确的......答案是两者都是正确的,因为有标准,但这些是由不同公司制作的不同编译器,因此GNU G++
和Clang
之间可能存在差异。 Clang
应该与G++
完全兼容,但事实并非如此。
答案 1 :(得分:-1)
#4形象不对,我很惊讶它编译。首先,double不能用作非类型模板参数。另一方面,类模板使用与用于部分排序的函数模板相同的规则。该标准提供了一个&#34;虚构&#34;为执行排序而生成的函数:
template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I> class X<I, I, int> { }; // #2
template<int I, int J> void f(X<I, J, int>); // A
template<int I> void f(X<I, I, int>); // B
对于您的示例,它看起来像这样:
template <typename T, T n1, T n2>
struct foo {
};
template <typename T, T n1, T n2>
void bar(foo<T, n1, n2>)
{
std::cout << "a";
}
template <typename T, T a>
void bar(foo<T, a, a>)
{
std::cout << "b";
}
模板参数推导用于确定哪个功能比另一个更专业。 double&
应该推导为double
,因此两个专业化应该相等,对bar(foo<double&, d, d>{});
来说也不明确。看到GCC和Clang抱怨:
GCC错误
main.cpp:14:6:注意:模板参数扣除/替换 失败:main.cpp:26:29:注意:不匹配的类型&#39; double&amp;&#39;和 &#39;双&#39;
bar(foo<double&, d, d>{}); ^
Clang错误
注意:候选模板被忽略:替换失败[用T = double&amp;]:推导出的非类型模板参数不一样 输入相应的模板参数(&#39; double&#39; vs&#39; double &安培;&#39)
同样,如果删除引用,他们都会正确地抱怨使用double
作为非类型模板参数。
我不打算测试其余的,但你可能会发现类似的结果。