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。整个计算是在未计算的上下文中进行的。因此,myZ
相当于quote
,myapply
适用于您的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
@Yakkapply
可能是一个更好的名字。但是我坚持用引用而不是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>