绑定元函数:接受类型和模板模板参数(接受任何东西)
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++ 中没有办法拥有可以是类型、值或模板的模板参数。所以这是你能得到的最好的。
不是为上述模式编写的模板需要包装起来,并且它们的参数 "lifted" 是类型。例如:
template<class T, class t>
using number_constant = std::integral_constant< T, t{} >;
using number_constant_z = Z<number_constant>;
有它的参数 "lifted" 从值到类型,然后用 Z
包裹它把它自己变成一个类型。
绑定现在读取:
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<?>
和 Bind_z
是一个包装模板的类型,returns 一个包装模板,并采用一个包装模板的类型作为它的第一个参数。
要使用它:
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>
的值、模板 a 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
的实例移动到标签中的type类型,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
。首先,你想要一些给定 "metafunction class" 的东西,并且一系列参数给你一个新类型:
template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
正如这里的实现所建议的那样,元函数 class 是一个具有名为 apply
.
的成员别名模板的元函数。
为了将 class 模板变成元函数 class,我们引入 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
设为元函数 class:
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
)和 元函数class(具有成员模板别名的类型,名为 apply
,例如 quote
)并在整个元编程中使用 仅这些概念代码。价值观和 class 模板是第二 class 公民。
我正在尝试编写一个 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++ 中没有办法拥有可以是类型、值或模板的模板参数。所以这是你能得到的最好的。
不是为上述模式编写的模板需要包装起来,并且它们的参数 "lifted" 是类型。例如:
template<class T, class t>
using number_constant = std::integral_constant< T, t{} >;
using number_constant_z = Z<number_constant>;
有它的参数 "lifted" 从值到类型,然后用 Z
包裹它把它自己变成一个类型。
绑定现在读取:
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<?>
和 Bind_z
是一个包装模板的类型,returns 一个包装模板,并采用一个包装模板的类型作为它的第一个参数。
要使用它:
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>
的值、模板 a 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
的实例移动到标签中的type类型,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
。首先,你想要一些给定 "metafunction class" 的东西,并且一系列参数给你一个新类型:
template <typename MCls, typename... Args>
using map = typename MCls::template apply<Args...>;
正如这里的实现所建议的那样,元函数 class 是一个具有名为 apply
.
为了将 class 模板变成元函数 class,我们引入 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
设为元函数 class:
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
)和 元函数class(具有成员模板别名的类型,名为 apply
,例如 quote
)并在整个元编程中使用 仅这些概念代码。价值观和 class 模板是第二 class 公民。