複合型replace_type<C, X, Y>
の型のすべての一致を に置き換えるメタ関数を作成しています。私は現在、これを の callable で適切に動作させることに取り組んでいます。X
C
Y
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?
);
};
このようにして、常に最初のパラメーターにアクセスして適切に置き換えてから、次のパラメーターに進み、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
構造体をラッパーとして使用して、2 つのパラメーター リストを区別しています。
パラメータ リストを 1 つずつ置き換えてstack
構造体に格納したら、あとはそれらをリストとして再度取り出して、 so: のように関数を構築する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;
};
上記のコードに構文エラーがある場合はご容赦ください。それはすでにかなり大きなファイルであり、関連する情報のみを抽出しようとしました。