0

C++ では、オーバーロードされた関数を異種のタプルにマップすることは可能ですか? 例えば:

double f(dobule);
size_t f(std::string);

auto t = std::make_tuple(3.14, "a string");
// should be the same as std::make_tuple(f(std::get<0>(t)), f(std::get<1>(t)));
map(f, make_tuple(3.14, "a string")); // type std::tuple<double, size_t>

の同じオーバーロードされたインスタンスを各タプル要素にマップするマップ関数を作成できますが(以下のコード)、の呼び出しからinsideの呼び出しまでfのオーバーロードの解決を延期する方法がわかりません。誰もこれを行う方法を考え出しましたか?fmapfmap

オーバーロードされた関数の単一のインスタンスをタプルにマップするコードは次のとおりです (seq と gens はこの回答https://stackoverflow.com/a/7858971/431282から取得されます):

// basically C++14's integer sequence
template<int ...>
struct seq { };

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...> {
  typedef seq<S...> type;
};

template<typename R, typename A, typename ...B, int ...S> auto
map_1(R (*f)(A), std::tuple<B...> &&t, seq<S...>)
  -> decltype(std::make_tuple(f(std::get<S>(t))...))
{
  return std::make_tuple(f(std::get<S>(t))...);
}

template<typename R, typename A, typename ...B> auto
map(R (*f)(A), std::tuple<B...> &&t)
  -> decltype(map_1(f, std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type()))
{
  return map_1(f, std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type());
}
4

1 に答える 1

2

問題は、引数にバインドされているときに関数のオーバーロードを解決する必要があるため、関数ポインターだけでは実行できないことです。オーバーロード解決を実行しないと、関数への関数ポインターを取得できません。重要なのは、最初に関数ポインターを取得しようとするのではなく、呼び出し時にオーバーロードを実行する関数オブジェクトを提供することです。

このために、プライマリ関数を次のように宣言します。

template<typename Func, typename ...B> auto
map(Func&& f, std::tuple<B...> &&t)
  -> decltype(map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type()))
{
  return map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type());
}

map_1次に、同様の方法で定義します。

次に、関数オブジェクトラッパーを作成できます

struct Wrapper
{
   template<typename T>
   auto operator()(T&& t) const -> decltype( f(std::forward<T>(t)) )
   {
       return f(std::forward<T>(t));
   }
};

そしてそれを呼び出すmap(Wrapper(), make_tuple(3.14, "a string"))

編集:C++ 14を使用している場合は、次のことができます(インスピレーションについて@MooingDuckに感謝します)

#define BINDOVERLOADED(X) [](auto&& t) { return X(std::forward<decltype(t)>(t)); }
auto x = map(BINDOVERLOADED(f), make_tuple(3.14, "a string"));

http://coliru.stacked-crooked.com/a/439f958827de8cf2を参照してください。

于 2014-05-01T19:12:17.867 に答える