这更像是一个概念性问题。我试图找到将双参数模板(参数是类型)转换为单参数模板的最简单方法。即,绑定(bind)其中一种类型。
这将是 boost/std 中 bind
的元编程等价物。我的示例包括一个可能的用例,即将 std::is_same
作为模板参数传递给采用单参数模板模板参数的模板 (std::is_same
是一个双参数模板),即 TypeList::FindIf
。 TypeList
未在此处完全实现,FindIf
也未完全实现,但您明白了。它采用“一元谓词”并返回该谓词为真的类型,如果不是这种类型,则返回 void
。
我有 2 个工作变体,但第一个不是单行的,第二个使用相当冗长的 BindFirst
装置,它不适用于非类型模板参数。有没有一种简单的方法来编写这样的单行代码?我相信我正在寻找的过程称为 currying
。
#include <iostream>
template<template<typename, typename> class Function, typename FirstArg>
struct BindFirst
{
template<typename SecondArg>
using Result = Function<FirstArg, SecondArg>;
};
//template<typename Type> using IsInt = BindFirst<_EqualTypes, int>::Result<Type>;
template<typename Type> using IsInt = std::is_same<int, Type>;
struct TypeList
{
template<template<typename> class Predicate>
struct FindIf
{
// this needs to be implemented, return void for now
typedef void Result;
};
};
int main()
{
static_assert(IsInt<int>::value, "");
static_assert(!IsInt<float>::value, "");
// variant #1: using the predefined parameterized type alias as predicate
typedef TypeList::FindIf<IsInt>::Result Result1;
// variant #2: one-liner, using BindFirst and std::is_same directly
typedef TypeList::FindIf< BindFirst<std::is_same, int>::Result>::Result Result2;
// variant #3: one-liner, using currying?
//typedef TypeList::FindIf<std::is_same<int, _>>::Result Result2;
return 0;
}
点击here用于在线编译器 GodBolt 中的代码。
最佳答案
我认为这样做的典型方法是保持类型世界中的所有内容。不要使用模板模板——它们很乱。让我们编写一个名为 ApplyAnInt
的元函数这将采用“元函数类”并应用 int
对它:
template <typename Func>
struct ApplyAnInt {
using type = typename Func::template apply<int>;
};
一个简单的元函数类可能只是检查给定类型是否为 int
:
struct IsInt {
template <typename T>
using apply = std::is_same<T, int>;
};
static_assert(ApplyAnInt<IsInt>::type::value, "");
现在的目标是支持:
static_assert(ApplyAnInt<std::is_same<_, int>>::type::value, "");
我们可以做到。我们将调用包含 _
的类型“lambda 表达式”,并编写一个名为 lambda
的元函数它将转发一个不是 lambda 表达式的元函数类,或者生成一个新的元函数,如果它是:
template <typename T, typename = void>
struct lambda {
using type = T;
};
template <typename T>
struct lambda<T, std::enable_if_t<is_lambda_expr<T>::value>>
{
struct type {
template <typename U>
using apply = typename apply_lambda<T, U>::type;
};
};
template <typename T>
using lambda_t = typename lambda<T>::type;
所以我们更新我们原来的元函数:
template <typename Func>
struct ApplyAnInt
{
using type = typename lambda_t<Func>::template apply<int>;
};
现在还剩下两件事:我们需要 is_lambda_expr
和 apply_lambda
.这些实际上一点也不糟糕。对于前者,我们将查看它是否是其中一种类型为 _
的类模板的实例化。 :
template <typename T>
struct is_lambda_expr : std::false_type { };
template <template <typename...> class C, typename... Ts>
struct is_lambda_expr<C<Ts...>> : contains_type<_, Ts...> { };
对于 apply_lambda
, 我们将替换 _
使用给定类型:
template <typename T, typename U>
struct apply_lambda;
template <template <typename...> class C, typename... Ts, typename U>
struct apply_lambda<C<Ts...>, U> {
using type = typename C<std::conditional_t<std::is_same<Ts, _>::value, U, Ts>...>::type;
};
实际上,这就是您所需要的。我将继续扩展它以支持 arg_<N>
作为读者的练习。
关于c++ - C++ 元编程中的模板柯里化(Currying),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27124560/