Partial template and icc specialization

Consider the following code:

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; } 

When I compile this with icc 16.0.1, I get the following message:

 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(); 

With clang 3.7.1 and gcc 5.3.0, this compiler (and the "instance of the special instance" is printed). Is it an icc error or the wrong code? It seems to me that the second specialization is strictly specialized than the first; it is identical to the first, except that it blocks the first parameter of the template.

Edit: I have to add: if this is a bug in icc, is there a good workaround?

+6
source share
1 answer

Yes, this is a bug in the ICC.


Both partial specializations correspond to your implementation, so go on to the rules for ordering a partial template for two synthesized functions:

 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> ); 

Partial ordering rules include the synthesis of new types for each argument of the template and an attempt to make a conclusion with each overload for the rest. First, we try to print U against Foo<_U1, _U2, std::integral_constant<int, _U2::value>> . This fails because _U1 does not match double . Therefore, the first overload is not at least as specialized as the second. Then we try to deduce T and U against Foo<double, _U3, std::integral_constant<int, _U3::value>> . This is done using T=double and U=_U3 . Therefore, the second overload is at least as specialized as the first.

As a result, the second overload is more specialized than the first. There is a unique, most specialized partial partialization that must be created (and is gcc and clang). ICC's inability to do this is a mistake.

+4
source

All Articles