template<class...> struct foo;
template<class X> struct foo<X>:std::true_type {};
template<class X, class Y, class Z> struct foo<X,Y,Z>:std::false_type {};
sotto qualsiasi abbinamento di modelli naive, foo
ha un'aerea infinita.
In pratica, ha un'aria di 1
o 3
.
In generale, la domanda "qual è l'aria di questo modello" è la domanda sbagliata. Piuttosto, "questi tipi possono essere passati a questo modello" o "quanti di questi tipi possono essere passati a questo modello" è più utile.
Cercare l'aria di un modello è come voler estrarre la firma da un oggetto callable. Se sai come chiamerai un oggetto, chiedendo "Posso chiamarlo in questo modo? è ragionevole; chiedere "dimmi come chiamarti" è quasi sempre fuorviato.
template<class...>struct types{using type=types;};
template<class types>struct types_length;
template<class...Ts>struct types_length<types<Ts...>>:
std::integral_constant<size_t, sizeof...(Ts)>
{};
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z,types<Ts...>,void_t<Z<Ts...>>>: std::true_type {};
};
template<template<class...>class Z, class...Ts>
struct can_apply : details::can_apply<Z,types<Ts...>> {};
Quanto sopra risponde alla domanda "Posso applicare alcuni tipi a un modello".
Ora, il più lungo prefisso di una serie di tipi è possibile applicare a un modello:
template<class T>struct tag{using type=T;};
namespace details {
template<class types, class=types<>>
struct pop_back {};
template<class T0, class...rhs>
struct pop_back<types<T0>, types<rhs...>>:types<rhs...> {};
template<class T0, class...Ts, class...rhs>
struct pop_back<types<T0, Ts...>, types<rhs...>>:
pop_back<types<T0,Ts...>,types<rhs...,T0>>
{};
template<class types>
using pop_back_t = typename pop_back<types>::type;
}
template<class types>
using pop_back = details::pop_back_t<types>;
namespace details {
template<template<class...>class Z, class types, class=void>
struct longest_prefix {};
template<template<class...>class Z, class...Ts>
struct longest_prefix<
Z,types<Ts...>,
std::enable_if_t<can_apply<Z,Ts...>>
>:
types<Ts...>
{};
template<template<class...>class Z,class T0, class...Ts>
struct longest_prefix<
Z,types<T0, Ts...>,
std::enable_if_t<!can_apply<Z, T0, Ts...>>
>:
longest_prefix<Z,pop_back_t<types<T0,Ts...>>>
{};
}
template<template<class...>class Z, class...Ts>
using longest_prefix =
typename details::longest_prefix<Z, types<Ts...>>::type;
namespace details {
template<class types>
struct pop_front;
template<>
struct pop_front<types<>> {};
template<class T0, class...Ts>
struct pop_front<types<T0,Ts...>>:types<Ts...>{};
template<class types>
using pop_front_t=typename pop_front<types>::type;
}
codice simile che prende un fascio di tipi e di un modello, e ripetutamente fette fuori il prefisso più lungo del fascio di tipi che possono essere passati al modello può essere scritto.
(Il codice sopra riportato contiene certamente errori di battitura).
template<class types>
using pop_front = details::pop_front_t<types>;
template<size_t n, template<class...>class Z, class T>
struct repeat : repeat< n-1, Z, Z<T> > {};
template<template<class...>class Z, class T>
struct repeat<0,Z,T> : tag<T> {};
template<size_t n, template<class...>class Z, class T>
using repeat_t = typename repeat<n,Z,T>::type;
template<template<class...>class Z, class types>
using longest_prefix_tail =
repeat_t<
types_length<longest_prefix<Z,Ts...>>{},
pop_front,
types<Ts...>
>;
ora si può prendere un modello e un sacco di tipi, e costruire un fascio di tipi derivanti dall'applicazione del modello per il più lungo prefisso del gruppo di tipi a sua volta.
Se siamo pazzi, potremmo persino fare il backtracking, in modo che se il nostro modello prende 2 o 3 elementi e lo alimentiamo 4, non proverebbe ad alimentarlo 3, quindi fallisce quando rimane 1 elemento - - Invece, potrebbe trovare il prefisso più lungo di ogni applicazione che consente alla coda di essere raggruppata in modo simile.
ha un modello di primaria prendere un 'T', poi specializzarsi con' arity> '' dove Args ... 'è un parametro di modello. Quindi ottieni la dimensione con 'sizeof ... (Args)'. –
0x499602D2
Sfortunatamente, ciò significa che non puoi passare solo il modello di classe, però. – chris
@ 0x499602D2 come indicato da chris, sfortunatamente non è "ragionevole" nel senso della domanda originale, poiché gli argomenti reali potrebbero non essere disponibili al punto in cui è necessario l'arità di un tipo di modello. – brunocodutra