Неопределенная реализация шаблона класса с нетиповыми пакетами параметров
Я пытался специализироваться 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 ответ
Это не может быть правдой. Это ошибка gcc (я не могу найти отчет об ошибке, может, об этом еще не сообщалось?).
Вы правы, специализация №2 должна быть выбрана. Поскольку есть две специализации, которые соответствуют, частичное упорядочение выбирает наиболее специализированную, которая в вашем случае является № 2 (double
первый параметр более специализирован, чем любой тип первого параметра).
Кроме того, clang компилирует ваш код без проблем.