lundi 24 juillet 2017

Ambiguous class template instantiation with nontype parameter packs

I was trying to specialize 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;
}

However, I got the following compiler errors:

[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

Here, especially the first error bothers me. I have tried to figure out why this is an ambiguous instantiation.

Shouldn't specialization #2 be chosen by the compiler?

If I avoid wrapping the non-type parameter pack int...i in std::integral_constant it compiles without any problem and the second specialization is chosen. The following example works:

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

Aucun commentaire:

Enregistrer un commentaire