[英]Recursive metafunction using variadic templates
我寫的元函數replace_type<C, X, Y>
是應該更換類型的所有比賽X
中的化合物類型C
與Y
。 我目前正在努力使這與C
callables一起使用。
這有效:
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?
);
};
這樣,我總是可以訪問第一個參數來適當地替換它,然后繼續下一個,並准備好另一個專門的元函數來處理nullary函數作為遞歸的終端條件。 問題是,如源代碼中所述,如何在此上下文中啟動遞歸?
更新
最小的例子:
#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
感謝Crazy Eddie,我已經能夠實現我想要的。 因為我花了這么長時間來理解這個野獸的答案,我認為其他人閱讀更詳細的解決方案可能會有所幫助。
我所做的事情可能是最長的實際意識:問題不在於如何分離函數參數,而是將它們轉換為替換參數的可變參數列表。 因此,這里的主要目標是找到一種正確替換每個參數的方法,並將其存儲到另一個單獨的參數列表中。 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
模板...需要查找如何從類型構建包。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.