Предполагая, что шаблон со списком параметров шаблона только для типа, следующая черта типа может извлечь первый аргумент типа:
template<typename T>
struct front {};
template<template<typename...> typename C, typename FirstT, typename... Args>
struct front<C<FirstT, Args...>> {using type = FirstT;};
template<typename T>
using front_t = typename front<T>::type;
template<typename...> struct foo{};
using std::is_same_v;
static_assert(is_same_v<front_t<foo<int, double>>, int>); // Ok
static_assert(is_same_v<front_t<foo<int, double>>, double>); // Fail (as expected)
Это, однако, не работает с шаблонами, которые имеют параметры-значения:
using std::array;
static_assert(is_same_v<front_t<array<int, 5>>, int>);
// error: no type named 'type' in 'struct front<std::array<int, 5> >'
Хорошо, теперь мне нужно учесть и любые значения параметров:
template<typename T>
struct front {};
// First parameter is a type, other parameters are types
template<template<typename...> typename C, typename FirstT, typename... Args>
struct front<C<FirstT, Args...>> {using type = FirstT;};
// First parameter is a type, other parameters are values
template<template<typename, auto...> typename C, typename FirstT, auto... Args>
struct front<C<FirstT, Args...>> {using type = FirstT;};
// First parameter is a value, other parameters are types
template<template<auto, typename...> typename C, auto FirstA, typename... Args>
struct front<C<FirstA, Args...>> {constexpr static const auto value = FirstA;};
// First parameter is a value, other parameters are values
template<template<auto...> typename C, auto FirstA, auto... Args>
struct front<C<FirstA, Args...>> {constexpr static const auto value = FirstA;};
// Avoid ambiguity if there's only a single type parameter
template<template<typename...> typename C, typename FirstT>
struct front<C<FirstT>> {using type = FirstT;};
// Avoid ambiguity if there's only a single value parameter
template<template<auto...> typename C, auto FirstA>
struct front<C<FirstA>> {constexpr static const auto value = FirstA;};
template<typename T>
using front_t = typename front<T>::type;
template<typename T>
const auto front_v = front<T>::value;
template<typename...> struct foo{};
template<auto...> struct bar{};
static_assert(std::is_same_v<front_t<foo<int>>, int>); // Ok
static_assert(std::is_same_v<front_t<foo<int, double>>, double>); // Fail (as expected)
static_assert(std::is_same_v<front_t<std::array<int, 5>>, int>); // Ok
static_assert(front_v<bar<5, 4>> == 5); // Ok
static_assert(front_v<bar<5, 4>> == 4); // Fail (as expected)
Но затем я попробую еще кое-что:
template<typename, typename, auto...> struct baz{};
static_assert(std::is_same_v<front_t<baz<int, int>>, int>);
// error: no type named 'type' in 'struct front<baz<int, int> >'
Это явно выходит из-под контроля.Теперь мне нужно не только беспокоиться о смешивании типов со значениями параметров, но и о порядке упорядочения этих параметров и писать специализацию для каждой их комбинации.Но все, что я хочу, это первый из этих параметров!Другие не должны иметь никакого значения.
Наконец, вопрос: могу ли я вообще "игнорировать" любые параметры шаблона, которые мне не нужны для этой черты типа?Под «обобщенно» я подразумеваю игнорирование как значений, так и типов.