gpt4 book ai didi

c++ - 如何反省可变参数模板模板参数的多样性?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:34:15 28 4
gpt4 key购买 nike

考虑一个假设的元函数 arity,它将任何元函数作为参数并返回其实际元数。

以下明显的方法是不可能的,因为根据语言标准命名的内部模板模板参数仅在本地定义。

template<template<typename... args> class f>
struct arity
{
static constexpr std::size_t value = sizeof...(args); //ERROR: undefined 'args'
};

即使是详尽的特化也不是一个替代方案,因为采用另一个模板类型的模板类型可能不会就内部模板的参数数量进行部分特化。

这让我想到了这个问题,我担心这个问题的答案是否定的。

Is there any reasonable way to introspect the actual arity of a template type?

我不希望 arity 的实际实现采用模板类型的形式,例如显而易见的方法,即任何可能是在编译时计算是可接受的“合理”解决方案,只要它不依赖于实际参数。

注意:为简单起见,假设只允许非可变元函数作为 arity 的参数。

最佳答案

template<class...> struct foo;
template<class X> struct foo<X>:std::true_type {};
template<class X, class Y, class Z> struct foo<X,Y,Z>:std::false_type {};

在任何朴素的模式匹配下,foo 都具有无限的空灵性。

在实践中,它的通风度为 13

一般来说,“这个模板的空洞是什么”这个问题是错误的问题。相反,“这些类型可以传递给这个模板”,或者“这些类型中有多少可以传递给这个模板”更有用。

寻找模板的空气性就像想要从可调用对象中提取签名一样。如果你知道你将如何调用一个对象,问“我可以这样调用它吗?怎么样?”是合理的;问“告诉我怎么称呼你”几乎总是被误导。

template<class...>struct types{using type=types;};
template<class types>struct types_length;
template<class...Ts>struct types_length<types<Ts...>>:
std::integral_constant<size_t, sizeof...(Ts)>
{};

template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;

namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};

template<template<class...>class Z, class...Ts>
struct can_apply<Z,types<Ts...>,void_t<Z<Ts...>>>: std::true_type {};
};
template<template<class...>class Z, class...Ts>
struct can_apply : details::can_apply<Z,types<Ts...>> {};

以上回答了“我可以将某些类型应用到模板中吗”这个问题。

现在,您可以将一组类型中最长的前缀应用于模板:

template<class T>struct tag{using type=T;};

namespace details {
template<class types, class=types<>>
struct pop_back {};
template<class T0, class...rhs>
struct pop_back<types<T0>, types<rhs...>>:types<rhs...> {};
template<class T0, class...Ts, class...rhs>
struct pop_back<types<T0, Ts...>, types<rhs...>>:
pop_back<types<T0,Ts...>,types<rhs...,T0>>
{};
template<class types>
using pop_back_t = typename pop_back<types>::type;
}
template<class types>
using pop_back = details::pop_back_t<types>;

namespace details {
template<template<class...>class Z, class types, class=void>
struct longest_prefix {};
template<template<class...>class Z, class...Ts>
struct longest_prefix<
Z,types<Ts...>,
std::enable_if_t<can_apply<Z,Ts...>>
>:
types<Ts...>
{};
template<template<class...>class Z,class T0, class...Ts>
struct longest_prefix<
Z,types<T0, Ts...>,
std::enable_if_t<!can_apply<Z, T0, Ts...>>
>:
longest_prefix<Z,pop_back_t<types<T0,Ts...>>>
{};
}
template<template<class...>class Z, class...Ts>
using longest_prefix =
typename details::longest_prefix<Z, types<Ts...>>::type;

namespace details {
template<class types>
struct pop_front;
template<>
struct pop_front<types<>> {};
template<class T0, class...Ts>
struct pop_front<types<T0,Ts...>>:types<Ts...>{};
template<class types>
using pop_front_t=typename pop_front<types>::type;
}

可以编写类似的代码,采用类型束和模板,并重复切掉可以传递给模板的类型束的最长前缀。

(以上代码肯定有错别字)

template<class types>
using pop_front = details::pop_front_t<types>;
template<size_t n, template<class...>class Z, class T>
struct repeat : repeat< n-1, Z, Z<T> > {};
template<template<class...>class Z, class T>
struct repeat<0,Z,T> : tag<T> {};
template<size_t n, template<class...>class Z, class T>
using repeat_t = typename repeat<n,Z,T>::type;
template<template<class...>class Z, class types>
using longest_prefix_tail =
repeat_t<
types_length<longest_prefix<Z,Ts...>>{},
pop_front,
types<Ts...>
>;

现在我们可以使用一个模板和一堆类型,并构建一个类型束,该束是将模板依次应用于这束类型中最长的前缀。

如果我们疯了,我们甚至可以做回溯,这样如果我们的模板有 2 或 3 个元素,我们给它 4 个,它就不会尝试给它 3 个,然后在剩下 1 个元素时失败 --相反,它可以找到每个应用程序的最长前缀,允许尾部被类似地捆绑。

关于c++ - 如何反省可变参数模板模板参数的多样性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29475427/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com