请考虑以下代码:
template <class T, class U, class V>
struct Foo { };
template <class T, class U>
struct Foo<T, U, std::integral_constant<int, U::value>> {
static void print()
{
std::cerr << "instantiated";
}
};
template <class U>
struct Foo<double, U, std::integral_constant<int, U::value>> {
static void print()
{
std::cerr << "instantiated special";
}
};
struct Bar {
static const int value = 0;
};
int main(int argc, char ** argv)
{
using Baz = Foo<double, Bar, std::integral_constant<int, 0>>;
Baz::print();
return 0;
}
当我使用icc 16.0.1编译它时,我收到以下消息:
main.cpp(38): error: more than one partial specialization matches the template argument list of class "Foo<double, Bar, std::integral_constant<int, 0>>"
"Foo<T, U, std::integral_constant<int, U::value>>"
"Foo<double, U, std::integral_constant<int, U::value>>"
Baz::print();
使用clang 3.7.1和gcc 5.3.0编译(和&#34;实例化特殊&#34;打印)。这是icc中的错误,还是我的代码不正确?对我来说,似乎很清楚,第二次专业化比第一次专业化更严格;除了锁定第一个模板参数之外,它与第一个相同。
编辑:我应该补充:如果这是icc中的错误,是否有一个好的解决方法?
答案 0 :(得分:4)
是的,这是ICC的一个错误。
两个部分特化都与您的实现相匹配,因此请在两个合成函数上进入部分模板排序规则:
template <class T, class U> void f(Foo<T, U, std::integral_constant<int, U::value> );
template <class U> void f(Foo<double, U, std::integral_constant<int, U::value> );
部分排序规则涉及为每个模板参数合成新类型,并尝试使用每个重载对其余模板进行推导。首先,我们尝试针对U
推断Foo<_U1, _U2, std::integral_constant<int, _U2::value>>
。此操作失败,因为_U1
与double
不匹配。所以第一次重载至少不如第二次重载。接下来,我们尝试针对T
推断U
和Foo<double, _U3, std::integral_constant<int, _U3::value>>
。这与T=double
和U=_U3
成功。所以第二次重载至少与第一次重载一样。
因此,第二个过载比第一个过载更专业。有一个独特的,最专业的部分局部化,应该被实例化(并且是通过gcc和clang)。 ICC未能这样做是一个错误。