绑定元函数:接受类型和模板模板参数(接受任何参数)
Bind metafunction: accept both types and template template parameters (accept anything)
我正在尝试编写一个Bind
元编程模板助手元函数,它将模板参数绑定到某些东西。
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>>{}, "");
但是如果MakePair
的模板参数是模板模板呢?还是简单的数值?
template<template<typename> class T0, template<typename> class T1>
struct MakePair0
{
using type = /*...*/;
};
template<template<typename...> class TF, template<typename> class... Ts>
struct Bind0 { /*...*/ }
// ...
template<int T0, int T1>
struct MakePair1
{
using type = /*...*/;
};
template<template<int...> class TF, int... Ts>
struct Bind1 { /*...*/ }
很多不必要的重复。如果模板参数混合在类型、模板模板和整型常量之间,就会变得难以管理。
像下面这段代码是可能的吗?
template<template<ANYTHING...> class TF, ANYTHING... Ts>
struct BindAnything
{
template<ANYTHING... TArgs>
using type = TF<Ts..., TArgs...>;
};
ANYTHING
将接受类型,模板模板,模板模板模板,整数值等
当我在做严肃的元编程时,我把所有都变成类型。
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...> >;
现在我们传递template<?> foo
作为Z<foo>
,它现在是一个类型。
std::integral_constant<T, t>
(以及更容易使用的别名)或template<class T, T* p> struct pointer_constant {};
,通过将它们转换为类型。
一旦一切都是类型,您的元编程就变得更加统一。模板只是成为一种类型的, apply_t
对其进行处理。
在c++中,模板实参不能同时是类型、值或模板。所以这是你能得到的最好的了。
没有为上述模式编写的模板需要打包,并将它们的参数"提升"为类型。例如:
template<class T, class t>
using number_constant = std::integral_constant< T, t{} >;
using number_constant_z = Z<number_constant>;
将其参数从值"提升"为类型,然后用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<?>
and Bind_z
是一个包装模板的类型,它返回一个包装模板,并接受一个包装模板的类型作为其第一个参数。
使用它:
template<class...>struct types{using type=types;};
using types_z=Z<types>;
template<class...Ts>
using prefix =apply_t< Bind_z, types_z, Ts... >;
using prefix_z = Z<prefix>;
prefix_z
接受一组类型,并生成types<?...>
的工厂,该工厂首先包含前缀Ts...
。
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 {}; }
在这里,类型由类型为tag<t>
的值表示,模板为Z<z>
,值为std::integral_constant<?>
。
template<class T>
constexpr tag<T> Tag = {};
template<template<class...>class z>
constexpr Z<z> Zag = {};
给出了获取分别代表类型和模板的值的方法。
#define TYPEOF(...) type_t<decltype(__VA_ARGS__)>
是一个宏,它从tag
的实例移动到标记中的类型类型,而Tag<?>
从类型移动到标记的实例。
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 >
很奇怪,但可以很有趣。
我想你在这里寻找quote
和map
。首先,您需要给定一个"元函数类",并通过一系列参数为您提供一个新类型:
template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
正如这里的实现所示,元函数类是具有名为apply
的成员别名模板的类。
要将类模板转换为元函数类,我们引入quote
:
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>
,但我宁愿让MakePair
直接成为元函数类:
struct MakePair2 {
template <typename T, typename U>
using apply = std::pair<T, U>;
};
using P = map<MakePair2, int, char>; // also std::pair<int, char>
避免了额外的::type
。
始终使用元函数(具有成员类型命名为type
的类型,例如map
)和元函数类(具有成员模板别名命名为apply
的类型,例如quote
)的概念,并且在整个元编程代码中仅使用这些概念。值和类模板是二等公民。
- 用于检查值是否为其任何参数的帮助程序函数
- C++ - 声明指向返回任何类型并获取任意数量参数的函数的指针
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- boost::p rogram_options 在指定意外的位置参数时不报告任何错误
- 使用聚合初始化模拟默认函数参数是否存在任何陷阱?
- 在将匿名对象作为参数传递时,不会调用任何构造函数
- 此函数如何在不传递任何参数的情况下工作?
- 高效的可变参数等于任何函数
- 如何声明一个接受任何大小的 2D 矢量参数?
- 如何在C++中接收任何类型的函数参数并获取函数内传递变量的类型?
- 在参数相关查找之前进行模板替换的任何方法(或解决方法?
- 部分专用化不使用其任何模板参数
- 创建一个构造函数,即Capabe获取任何数量的参数
- C++任何非类型参数的模板专用化
- 有没有办法跟踪任何编译器的模板参数推导?
- C 模板功能是否有任何方法可以采用n个参数
- 类介绍 (c++) 项目希望我们创建两个构造函数,但它们都不需要任何参数 - 我应该在这里做什么?
- 创建带有任何参数的 std::functions 的unordered_map?
- 将任何数据类型/对象作为参数传递以确定其大小