C++ 绑定元函数:接受类型和模板参数(接受任何内容)

C++ 绑定元函数:接受类型和模板参数(接受任何内容),c++,templates,metaprogramming,c++14,template-templates,C++,Templates,Metaprogramming,C++14,Template Templates,我正在尝试编写一个Bindmetaprogramming template helper元函数,将模板参数绑定到某个对象 我有一个简单模板元函数的工作实现: template<typename T0, typename T1> struct MakePair { using type = std::pair<T0, T1>; }; template<template<typename...> class TF, typename... Ts&g

我正在尝试编写一个
Bind
metaprogramming template helper元函数,将模板参数绑定到某个对象

我有一个简单模板元函数的工作实现:

template<typename T0, typename T1>
struct MakePair
{
    using type = std::pair<T0, T1>;
};

template<template<typename...> class TF, typename... Ts>
struct Bind
{
    template<typename... TArgs>
    using type = TF<Ts..., TArgs...>;
};

using PairWithInt = typename Bind<MakePair, int>::type;
static_assert(std::is_same<PairWithInt<float>, MakePair<int, float>>{}, "");
template<template<class...>class z, class...Ts>
constexpr auto apply_f( Z<z>, tag<Ts>... )
-> tag<z<Ts...>> { return {}; }
很多不必要的重复。如果模板参数在类型、模板模板和整型常量之间混合,则会变得不可管理

下面的代码可能吗

template<template<ANYTHING...> class TF, ANYTHING... Ts>
struct BindAnything
{
    template<ANYTHING... TArgs>
    using type = TF<Ts..., TArgs...>;
};
模板
结构绑定任何东西
{
模板
使用类型=TF;
};

任何东西
都可以接受类型、模板、模板、整数值等。

当我进行严肃的元编程时,我会将所有东西都转换为类型

template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

template<template<class...>class> struct Z {};
template<class Z, class...Ts>
struct apply {};
template<template<class...>class z, class...ts>
struct apply< Z<z>, ts... >:
  tag< z<ts...> >
{};
template<class Z, class...Ts>
using apply_t = type_t< apply<Z, Ts...> >;
将其参数从值“提升”到类型,然后用
Z
将其自身包装为类型

Bind现在的内容如下:

template<class z, class... Ts>
struct Bind {
  template<class... More>
  using type_base = apply_t< z, Ts..., More... >;
  using type = Z<type_base>;
};
template<class Z, class...Ts>
using Bind_t = type_t<Bind<Z,Ts...>>; // strip ::type
using Bind_z = Z<Bind_t>; // quote into a Z<?>

prefix_z
获取一组类型,并生成一个
类型工厂我想您在这里寻找
quote
map
。首先,您需要一个给定“元函数类”和一系列参数的对象,它为您提供了一种新类型:

template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
以上内容足以执行以下操作:

using T = map<quote<std::tuple>, int, char, double>;
这样就避免了额外的
::type


始终使用元函数(成员类型定义为
类型
,例如
映射
)和元函数类(成员模板别名为
的类型应用
,例如
引用
)的概念,并在元编程代码中仅使用这些概念。值和类模板是二等公民

与简单地写出模板相比,这样做的好处是什么?反正都是静态/编译时。看看我刚写的这个用例,我在写一些代码时遇到了它。太长了,读不下去了,“C++中没有一个模板可以是一个类型,一个值或者一个模板。”重载函数模板可以用一个模板参数来完成。不过,这需要
decltype
杂乱无章。@dyp-true,我们可以使用boost-hana风格,作为
constexpr
函数进行元编程。但即使在那里,拥有
Z
也很有用,因为它允许您将模板作为值传递。您所讨论的重载解决方案最终仍然是指数爆炸式的——如何编写一个函数重载,将模板作为其第一个模板参数,每个参数(传递给函数的模板)可以是模板、大小、整数、指向函数的指针或类型?你真的不能…Ad指数爆炸:这就是为什么我说“一个模板参数”:)它可以用来编写一个通用适配器:
decltype(adapt())
,其中
X
可以是一个类型、模板或值(或一个函数,但没有重载集,是一组固定的签名)。但是由于
decltype
混乱,可能最好编写三个单独命名的适配器。@dyp假设
X
模板
另一个
X
模板
。另一个是
模板
。有无限多的
模板一旦我们得到constexpr lambdas,使用对象甚至可能成为一种语法上令人愉悦的方法:--等等,我想我们甚至不需要constexpr lambdas。整个计算是在未计算的上下文中进行的。因此,my
Z
相当于
quote
,my
apply
适用于您的
map
,但您可能使用了更多的标准名称(对于Monad是
map
haskell的
fmap
,还是
=/code>?)。不同之处在于,您的
map
依赖于
T::apply@Yakk大部分。我想主要的区别是
map
适用于任何元函数类,而
apply\t
只适用于
Z
s。雅克·哈斯凯尔在我的“有一天,我会学习这个”列表上已经有很多年了,但它基本上是
fmap
。我不完全确定
>=
是做什么的,所以不能说是一种方式还是另一种方式。nod,它使直接元函数变得更容易,而不必执行系统要求的3个步骤(首先,一个生成类型的结构,然后一个
type\u t
展开,然后一个
Z
包装)。我不喜欢
map
的名字,但是:对我来说,
map
应该是
list
,而不是
Z
@Yakk
apply
可能是一个更好的名字。但是我坚持用
引用
而不是
Z
:-P
apply_t< apply_t< prefix_z, int, double, char >, std::string >
types< int, double, char, std::string >
template<template<class...>class z, class...Ts>
constexpr auto apply_f( Z<z>, tag<Ts>... )
-> tag<z<Ts...>> { return {}; }
template<class T>
constexpr tag<T> Tag = {};
template<template<class...>class z>
constexpr Z<z> Zag = {};
#define TYPEOF(...) type_t<decltype(__VA_ARGS__)>
TYPEOF( apply_f( apply_f( Zag<prefix>, Tag<int>, Tag<double>, Tag<char> ), Tag<std::string> ) )
apply_t< apply_t< prefix_z, int, double, char >, std::string >
template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
template <template <typename...> class C>
struct quote {
    template <typename... Args>
    using apply = C<Args...>;
};
using T = map<quote<std::tuple>, int, char, double>;
std::tuple<int, char, double>
using P = map<quote<MakePair>, int, char>::type; // std::pair<int, char>
struct MakePair2 {
    template <typename T, typename U>
    using apply = std::pair<T, U>;
};

using P = map<MakePair2, int, char>; // also std::pair<int, char>