使用可变参数模板的递归元函数
Recursive metafunction using variadic templates
我正在编写一个元函数replace_type<C, X, Y>
,它应该用Y
替换复合类型C
中所有X
类型的匹配项。我目前正在努力使其与C
中的可调用对象一起使用。
这有效:
template replace_type<
typename C, typename X, typename Y,
typename First
>
struct replace_type<C(First), X, Y>
{
typedef typename replace_type<
C, X, Y
>::type type(
typename replace_type<
First, X, Y
>::type
);
};
template replace_type<
typename C, typename X, typename Y,
typename First, typename Second
>
struct replace_type<C(First, Second), X, Y>
{
typedef typename replace_type<
C, X, Y
>::type type(
typename replace_type<
First, X, Y
>::type,
typename replace_type<
Second, X, Y
>::type
);
};
但这显然是非常有限的。在我的脑海中,似乎很明显我应该在这里使用可变参数模板,但是当我实际尝试应用它时,我很快注意到我不知道如何将其融入这个方案。
我想像这样实现它:
template replace_type<
typename C, typename X, typename Y,
typename First, typename... Args
>
struct replace_type<C(First, Args...), X, Y>
{
typedef typename replace_type<
C, X, Y
>::type type(
typename replace_type<
First, X, Y
>::type,
// How to recursively do the same with the rest of the arguments?
);
};
这样,我总是可以访问第一个参数以适当地替换它,然后继续下一个参数,并准备好另一个专门的元函数来处理空函数作为递归的终端条件。问题是,如源代码中所述,在这种情况下如何开始递归?
更新
最小示例:
#include <type_traits>
namespace type_replace_helper
{
template <typename, typename, typename>
struct type_replace_base;
}
template <typename C, typename X, typename Y>
struct type_replace
{
typedef typename std::conditional<
std::is_same<C, X>::value,
Y,
typename type_replace_helper::type_replace_base<
C, X, Y
>::type
>::type type;
};
namespace type_replace_helper
{
template <typename C, typename X, typename Y>
struct type_replace_base
{
typedef C type;
};
template <typename C, typename X, typename Y>
struct type_replace_base<C(), X, Y>
{
typedef typename type_replace<
C, X, Y
>::type type();
};
template <
typename C, typename X, typename Y,
typename First
>
struct type_replace_base<C(First), X, Y>
{
typedef typename type_replace<
C, X, Y
>::type type(
typename type_replace<
First, X, Y
>::type
);
};
template <
typename C, typename X, typename Y,
typename First, typename Second
>
struct type_replace_base<C(First, Second), X, Y>
{
typedef typename type_replace<
C, X, Y
>::type type(
typename type_replace<
First, X, Y
>::type,
typename type_replace<
Second, X, Y
>::type
);
};
}
int main()
{
static_assert(std::is_same<
type_replace<int(int, int), int, long>::type,
long(long, long)
>::value, "int should be replaced by long");
return 0;
}
更新 2
多亏了疯狂的埃迪,我才能实现我想要的。因为我花了很长时间才理解这个野兽的答案,所以我认为其他人阅读更冗长的解决方案可能会有所帮助。
我花了很长时间才真正意识到的事情:问题实际上不在于如何分离函数参数,而是将它们转换为替换参数的可变参数列表。因此,这里的主要目标是找到一种方法来正确替换每个参数,并将其存储到另一个单独的参数列表中。Eddy 的解决方案使用 stack
结构作为包装器来区分两个参数列表,一个被替换,一个有剩余的事情要做。
一旦参数列表被一一替换并存储在stack
结构中,剩下要做的就是将它们再次作为列表拉出并构造函数,如下所示:typedef T type(Params...);
,仅此而已。
在我的编码风格中,这显示为:
template <typename...>
struct stack {};
// Definition only to specialize for actual stacks
template <
typename X, typename Y,
typename Stack, typename... Todo
>
struct list_converter;
// No more arguments to convert, return the gathered stack
template <
typename X, typename Y,
typename... Elems
>
struct list_converter<X, Y, stack<Elems...>>
{
typedef stack<Elems...> type;
};
// Push replaced argument to stack and go to the next argument
template <
typename X, typename Y,
typename... Elems,
typename First, typename... Todo
>
struct list_converter<X, Y, stack<Elems...>, First, Todo...>
{
typedef typename list_converter<
X, Y,
stack<
typename replace_type<First, X, Y>::type,
Elems...
>,
Todo...
>::type type;
};
// Definition only again for stack specialization
template <
typename C, typename X, typename Y,
typename Stack
>
struct function_builder;
// Pull out argument list from the stack and build a function
template <
typename C, typename X, typename Y,
typename... Elems
>
struct function_builder<C, X, Y, stack<Elems...>>
{
typedef typename replace_type<
C, X, Y
>::type type(Elems...);
};
// Specialization for function replacements
// Builds function with replaced return type, and converted
// argument list (recursion starts with empty stack)
template <
typename C, typename X, typename Y,
typename... Params
>
struct replace_type<C(Params...), X, Y>
{
typedef typename function_builder<
C, X, Y,
typename list_converter<
X, Y,
stack<>,
Params...
>::type
>::type type;
};
如果上面的代码中有一些语法错误,请原谅我;它已经是一个相当大的文件,我试图只提取相关信息。
可变参数包的扩展可以处理所谓的模式。因此,您可以将一个部分专用化用于所有内容。
template replace_type<
typename R, typename... Args,
typename X, typename Y
>
struct replace_type<R(Args...), X, Y>
{
typedef typename replace_type<
R, X, Y
>::type type(
typename replace_type<
Args, X, Y
>::type...
);
};
template < typename ... A >
struct stack { };
template < typename Stack, typename T >
struct push_front;
template < typename T, typename ... A >
struct push_front<stack<A...>,T> {
typedef stack<T, A ... > type;
};
template < typename Ret, typename Args >
struct build_fun;
template < typename Ret, typename ... A >
struct build_fun<Ret, stack<A...> > {
typedef Ret(*fptr)(A...);
typedef decltype(*static_cast<fptr>(0)) type;
};
template < typename Match, typename Rep, typename Target >
struct replace_match { typedef Target type; };
template < typename Match, typename Rep >
struct replace_match<Match, Rep, Match> { typedef Rep type; };
template < typename Match, typename Rep, typename ... Types >
struct replace;
template < typename Match, typename Rep, typename Head, typename ... Tail >
struct replace<Match,Rep,Head,Tail...>
{
typedef typename replace_match<Match,Rep,Head>::type my_match;
typedef typename replace<Match, Rep, Tail...>::type next_set;
typedef typename push_front<next_set, my_match>::type type;
};
template < typename Match, typename Rep >
struct replace<Match,Rep>
{
typedef stack<> type;
};
template < typename Sig, typename Match, typename Rep>
struct replace_fun_args;
template < typename R, typename Match, typename Rep, typename ... Args >
struct replace_fun_args
{
typedef typename replace<Match, Rep, Args...>::type arg_stack;
typedef typename build_fun<R,arg_stack>::type type;
};
#include <iostream>
#include <typeinfo>
int main() {
replace<int,char,double,unsigned int, int, char*>::type t;
std::cout << typeid(build_fun<void,decltype(t)>::type).name() << std::endl;
}
可能有一种方法可以只使用包而不是stack
模板......需要查找如何从类型构建包。
- 递归函数计算序列中的平方和(并输出过程)
- 如何在Elixir中调用递归函数并行
- 递归函数有效,但无法记忆
- 为什么我的递归函数按降序打印,然后按升序打印?
- 为什么递归函数的最终输出是 5?
- 有没有办法使用递归函数找到数组中最小值的 INDEX?C++
- 如何将记忆应用于此递归函数?
- 如何从递归函数中完全返回,该函数给出了每个函数结果的累积相加?
- 无穷大而循环时具有递归函数
- 即使没有调用这个递归函数,它是如何工作的?
- 如何使此递归函数从给定的起始位置返回最小的整数?
- 此递归函数的每次迭代的值存储在哪里?
- 可以清除递归函数中的变量吗?
- 如何在递归函数调用中返回当前函数值
- 递归函数 c++ 的复杂性
- 这个递归函数有什么作用?运行时的复杂性是多少?
- 任何人都可以查明我的递归函数中的错误吗?
- 递归函数的返回类型推导
- 递归函数调用在后台工作
- 查找存储在二叉搜索树的所有非叶子中的数据总和?(返回整数的独立递归函数