绑定元功能:接受类型和模板模板参数(接受任何内容) [英] Bind metafunction: accept both types and template template parameters (accept anything)

查看:92
本文介绍了绑定元功能:接受类型和模板模板参数(接受任何内容)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个Bind元编程模板帮助程序元函数,该函数将模板参数绑定到某些东西.

I'm trying to write a Bind metaprogramming template helper metafunction that binds a template parameter to something.

对于简单的模板元功能,我有一个可行的实现方式:

I have a working implementation for simple template metafunctions:

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的模板参数是模板模板怎么办?还是简单的数值?

But what if MakePair's template arguments were template templates? Or simple numerical values?

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 { /*...*/ }

很多不必要的重复.如果在类型,模板模板和整数常量之间混合使用模板参数,则将变得难以管理.

A lot of unnecessary repetition. It gets unmanageable if template arguments are mixed between types, template templates, and integral constants.

是否可能出现以下代码?

Is something like the following piece of code possible?

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

ANYTHING将接受类型,模板模板,模板模板模板,整数值等...

ANYTHING would accept types, template templates, template template templates, integral values, etc...

推荐答案

在进行认真的元编程时,我将一切转换为类型.

When I'm doing serious metaprogramming, I turn everything into types.

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>,它现在是一种类型.

now we pass template<?> foo around as Z<foo>, and it is now a type.

可以使用常量std::integral_constant<T, t>(并且更容易使用相同的别名)或template<class T, T* p> struct pointer_constant {};将常量转换为类型,从而对常量进行类似的处理.

Similar things can be done for constants, using std::integral_constant<T, t> (and easier to use aliases of same), or template<class T, T* p> struct pointer_constant {};, by turning them into types.

一旦一切都是一种类型,您的元编程将变得更加统一.模板只是一种种类apply_t可以根据其来执行操作.

Once everything is a type, your metaprogramming becomes more uniform. Templates just become a kind of type on which apply_t does things to.

在C ++中,没有办法使用可以为类型,值或模板的模板参数.因此,这是您可以获得的最好的东西.

There is no way in C++ to have a template argument that can be a type, a value or a template. So this is about the best you can get.

模板需要包装,并且其参数提升"为类型.例如:

templates not written for the above pattern need to be wrapped up, and their arguments "lifted" to being types. As an example:

template<class T, class t>
using number_constant = std::integral_constant< T, t{} >;
using number_constant_z = Z<number_constant>;

已将其参数从值提升"为类型,然后用Z包裹以将其自身转换为类型.

has had its arguments "lifted" from values to types, and then it has been wrapped with a Z to turn itself into a type.

绑定现在显示为:

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是包装模板的类型,该类型返回包装的模板,并将包装模板的类型作为其第一个参数.

and Bind_z is a type wrapping a template that returns a wrapped template, and takes a type that wraps a template as its first argument.

要使用它:

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....

prefix_z takes a set of types, and generates a factory of types<?...> that will contain the prefix Ts... first.

apply_t< apply_t< prefix_z, int, double, char >, std::string >

types< int, double, char, std::string >

在线示例.

还有另一种有趣的方法:在函数中进行元编程:

There is another fun approach: do metaprogramming in functions:

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<?>表示.

here, types are represented by values of type tag<t>, templates a Z<z> and values as std::integral_constant<?>.

这两个:

template<class T>
constexpr tag<T> Tag = {};
template<template<class...>class z>
constexpr Z<z> Zag = {};

为您提供获取分别代表类型和模板的值的方法.

give you ways to get values that represent types and templates respectively.

#define TYPEOF(...) type_t<decltype(__VA_ARGS__)>

是一个宏,它从tag的实例移动到标签中的类型,而Tag<?>从类型的标签移动到标签的实例.

is a macro that moves from an instance of a tag to type type in the tag, and Tag<?> moves from a type to an instance of a 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 >

奇怪,但可能很有趣.

这篇关于绑定元功能:接受类型和模板模板参数(接受任何内容)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆