这是一种通用方法——用于二进制折叠的 TMP,使用 C++14。首先,让我们定义基本的组合操作:
#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;
};
现在是真正的fold 技工:
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>> {};
接下来,我们需要一种通过绑定从二元特征创建一元特征的方法:
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> {};
};
最后,一个辅助包装器来组合应用一元谓词的结果:
template <typename Op, template <typename> class UPred, typename ...Args>
struct fold_pred : fold<Op, UPred<Args>::value...> {};
就是这样。现在让我们开始工作吧:
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';
}
在 C++17(或 C++1z,更确切地说)中,由于新的折叠表达式,您可以用更少的代码编写直接解决方案。例如:
template <template <typename> class UPred, typename ...Args>
static constexpr bool pred_all = (UPred<Args>::value && ...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unary fold
用法:
static_assert(pred_all<maybe_double, int, float>);