绑定元函数:接受两种类型和模板模板参数(接受任何东西)

Vit*_*meo 3 c++ templates metaprogramming template-templates c++14

我正在尝试编写一个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>>{}, "");
Run Code Online (Sandbox Code Playgroud)

但是,如果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 { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

很多不必要的重复.如果在类型,模板模板和整数常量之间混合模板参数,则无法管理.

类似下面的代码可能吗?

template<template<ANYTHING...> class TF, ANYTHING... Ts>
struct BindAnything
{
    template<ANYTHING... TArgs>
    using type = TF<Ts..., TArgs...>;
};
Run Code Online (Sandbox Code Playgroud)

ANYTHING 会接受类型,模板模板,模板模板模板,积分值等...

Yak*_*ont 9

当我进行严肃的元编程时,我将所有内容都变成了类型.

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...> >;
Run Code Online (Sandbox Code Playgroud)

现在我们传遍template<?> fooZ<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>;
Run Code Online (Sandbox Code Playgroud)

已经将它的参数从值"提升"到类型,然后它被包裹着一个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<?>
Run Code Online (Sandbox Code Playgroud)

并且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>;
Run Code Online (Sandbox Code Playgroud)

prefix_z采用一组类型,并生成一个首先types<?...>包含前缀的工厂Ts....

apply_t< apply_t< prefix_z, int, double, char >, std::string >
Run Code Online (Sandbox Code Playgroud)

types< int, double, char, std::string >
Run Code Online (Sandbox Code Playgroud)

实例.

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

template<template<class...>class z, class...Ts>
constexpr auto apply_f( Z<z>, tag<Ts>... )
-> tag<z<Ts...>> { return {}; }
Run Code Online (Sandbox Code Playgroud)

这里,类型由类型tag<t>,模板a Z<z>和值的值表示std::integral_constant<?>.

这两个:

template<class T>
constexpr tag<T> Tag = {};
template<template<class...>class z>
constexpr Z<z> Zag = {};
Run Code Online (Sandbox Code Playgroud)

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

#define TYPEOF(...) type_t<decltype(__VA_ARGS__)>
Run Code Online (Sandbox Code Playgroud)

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

TYPEOF( apply_f( apply_f( Zag<prefix>, Tag<int>, Tag<double>, Tag<char> ), Tag<std::string> ) )
Run Code Online (Sandbox Code Playgroud)

apply_t< apply_t< prefix_z, int, double, char >, std::string >
Run Code Online (Sandbox Code Playgroud)

奇怪,但可能很有趣.