使用非类型参数包进行不明确的类模板实例化

时间:2017-07-24 19:27:43

标签: c++ c++11 partial-specialization non-type

我试图专攻Expr

#include <tuple>
#include <type_traits>
#include <iostream>

template<class Tp, class List> 
struct Expr {
    Expr(){std::cout << "0"<< std::endl;};
};

//specialization #1
template<class Tp, int...i>
struct Expr<Tp,std::tuple<std::integral_constant<int,i>...>> {

    Expr(){std::cout << "1"<< std::endl;};
};

//specialization #2
template<int...i>
struct Expr<double,std::tuple<std::integral_constant<int,i>...>> {

    Expr(){std::cout << "2"<< std::endl;};
};

int main() {

    typedef std::tuple<std::integral_constant<int,1>> mylist;

    Expr<double,mylist> test{};

    return 0;
}

但是,我收到了以下编译器错误:

[x86-64 gcc 6.3] error: ambiguous template instantiation for 'struct Expr<double, std::tuple<std::integral_constant<int, 1> > >'
[x86-64 gcc 6.3] error: variable 'Expr<double, std::tuple<std::integral_constant<int, 1> > > test' has initializer but incomplete type

在这里,尤其是第一个错误困扰着我。我试图弄清楚为什么这是一个模棱两可的实例。

编译器不应该选择specialization #2吗?

如果我避免在int...i中包装非类型参数包std::integral_constant,它会毫无问题地编译,并选择第二个特化。以下示例有效:

#include <tuple>
#include <type_traits>
#include <iostream>

template<class Tp, class List> 
struct Expr {
    Expr(){std::cout << "0"<< std::endl;};
};

//specialization #1
template<class Tp, class...args>
struct Expr<Tp,std::tuple<args...>> {

    Expr(){std::cout << "1"<< std::endl;};
};

//specialization #2
template<class...args>
struct Expr<double,std::tuple<args...>> {

    Expr(){std::cout << "2"<< std::endl;};
};

int main() {

    typedef std::tuple<std::integral_constant<int,1>> mylist;

    Expr<double,mylist> test{};

    return 0;
}

1 个答案:

答案 0 :(得分:1)

这不可能是正确的。这是一个gcc bug(我找不到它的bug报告,也许还没有报道呢?)。

你是对的,必须选择专业化#2。因为有两个匹配的特化,部分排序选择最专业的一个,在你的情况下是#2(double,因为第一个参数比任何类型更专业作为第一个参数)。

此外,clang会编译您的代码without any problems