Qui è un approccio generico – una TMP per la piegatura binario, usando C++ 14. In primo luogo, definiamo le operazioni che conciliano la base:
#include <type_traits>
struct and_op
{
using type = bool;
using identity = std::true_type;
template <bool A, bool B> static constexpr bool value = A && B;
};
struct or_op
{
using type = bool;
using identity = std::false_type;
template <bool A, bool B> static constexpr bool value = A || B;
};
Ora l'attuale fold
meccanico:
template <typename Op, typename Op::type...>
struct fold;
template <typename Op>
struct fold<Op> : Op::identity {};
template <typename Op, typename Op::type Val>
struct fold<Op, Val>
: std::integral_constant<typename Op::type
, Val> {};
template <typename Op, typename Op::type Val, typename Op::type... Tail>
struct fold<Op, Val, Tail...>
: std::integral_constant<typename Op::type
, Op::template value<Val, fold<Op, Tail...>::value>> {};
Avanti, abbiamo bisogno di un modo per creare tratti unarie da tratti binari legandosi:
template <template <typename, typename> class BPred, typename T>
struct bind_pred
{
template <typename U>
struct pred_1st : std::integral_constant<bool, BPred<T, U>::value> {};
template <typename U>
struct pred_2nd : std::integral_constant<bool, BPred<U, T>::value> {};
};
Infine, un wrapper di supporto per combinare il risultato dell'applicazione di un predicato unario:
template <typename Op, template <typename> class UPred, typename ...Args>
struct fold_pred : fold<Op, UPred<Args>::value...> {};
Questo è tutto. Ora veniamo al lavoro:
template <typename T>
using maybe_double = bind_pred<std::is_convertible, double>::pred_2nd<T>;
#include <iomanip>
#include <iostream>
int main()
{
std::cout
<< std::boolalpha
<< fold_pred<and_op, maybe_double, int, float>::value << '\n'
<< fold_pred<and_op, maybe_double, int, float, void>::value << '\n';
}
In C++ 17 (o C++ 1z, piuttosto), è possibile scrivere soluzioni dirette con codice meno grazie alle nuove espressioni piega. Per esempio:
template <template <typename> class UPred, typename ...Args>
static constexpr bool pred_all = (UPred<Args>::value && ...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unary fold
Usage:
static_assert(pred_all<maybe_double, int, float>);
Neat, ma non ha un'ovvia generalizzazione a "any is true"? –
@KerrekSB "any is true" = non "tutto falso". Quindi definisci 'all_false' lungo linee simili e fai' template usando any_true = std :: integral_constant :: value>; ' –
Ah, ovviamente :-) –