Я предлагаю следующее:
// ground case: no more types, so empty
template <typename ...>
struct fnes_helper
{ using type = empty; };
// the first type is T and isn't empy; so T
template <typename T, typename ... Ts>
struct fnes_helper<T, Ts...>
{ using type = T; };
// the first type is empty; so recursion
template <typename ... Ts>
struct fnes_helper<empty, Ts...> : public fnes_helper<Ts...>
{ };
template <typename ... Ts>
using first_non_empty_subtype
= typename fnes_helper<typename Ts::subtype...>::type;
Заметьте, что более специализированная версия fnes_helper
- это версия с типом empty
в первой позиции, так что в этом случае используется версия.Следует за другой специализацией, которая имеет общий тип T
в первой позиции, и, наконец, у нас есть основная версия, которая выбрана в других случаях, поэтому, когда список типов пуст.
Также не забудьтедобавить {}
или ::value
после std::is_same
в static_assert()
тестах
static_assert(std::is_same<int, first_non_empty_subtype<E,E,I>>{},
"the first non-empty subtype should be 'int'");
static_assert(std::is_same<double, first_non_empty_subtype<E,D,I>>{},
"the first non-empty subtype should be 'double'");
static_assert(std::is_same<empty, first_non_empty_subtype<E,E,E>>{},
"since all subtypes are empty, the result is empty");