以下是一个简单的模板部分特化:
// #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上的结果# | 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 |
哪一个是对的?代码:http://coliru.stacked-crooked.com/a/45ba16c9f021fd84
最佳答案
#4格式不正确,我很惊讶它可以编译。一方面,不能将double用作非类型模板参数。另一方面,类模板使用与函数模板相同的规则进行部分排序。该标准提供了为执行排序而生成的“虚构”函数的示例:
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>{});
也是模棱两可的。 Lo看到GCC和Clang提示:同样,如果删除引用,他们俩都会正确地提示将
double
用作非类型模板参数。我将不测试其余部分,但您可能会发现类似的结果。
关于c++ - 整数非类型参数和非整数非类型的模板部分特化,g++和clang之间的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37369129/