部分模板专业化和icc

时间:2016-05-13 17:40:16

标签: c++ templates c++11

请考虑以下代码:

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中的错误,是否有一个好的解决方法?

1 个答案:

答案 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>>。此操作失败,因为_U1double不匹配。所以第一次重载至少不如第二次重载。接下来,我们尝试针对T推断UFoo<double, _U3, std::integral_constant<int, _U3::value>>。这与T=doubleU=_U3成功。所以第二次重载至少与第一次重载一样。

因此,第二个过载比第一个过载更专业。有一个独特的,最专业的部分局部化,应该被实例化(并且是通过gcc和clang)。 ICC未能这样做是一个错误。