boost::range::combine
を単なる製品としてデカルトパワーとして使用したいと思います。boost :: range ::繰り返し引数と組み合わせる
そのような式の代わりに、boost::range::combine(myRange, myRange, myRange);
は、myCombine(myRange, 3);
のようなものを書きます。
どのように実装できますか?
boost::range::combine
を単なる製品としてデカルトパワーとして使用したいと思います。boost :: range ::繰り返し引数と組み合わせる
そのような式の代わりに、boost::range::combine(myRange, myRange, myRange);
は、myCombine(myRange, 3);
のようなものを書きます。
どのように実装できますか?
これをC++ 17またはC++ 14で実装する方がはるかに簡単ですっきりしていますが、c++11というタグが付いているので、ここには準拠した実装があります。ここでは、同じ引数を持つ関数オブジェクトf
を呼び出す一般的な方法をN
回繰り返します。
まず、我々は、一般的な関数オブジェクトf
の最初の引数を結合する方法を必要として、任意の数の引数受諾:次に
template <typename TF, typename T>
struct bound
{
TF _f;
T _x;
template <typename TFFwd, typename TFwd>
bound(TFFwd&& f, TFwd&& x)
: _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)}
{
}
template <typename... Ts>
auto operator()(Ts&&... xs)
-> decltype(_f(_x, std::forward<Ts>(xs)...))
{
return _f(_x, std::forward<Ts>(xs)...);
}
};
template <typename TF, typename T>
auto bind_first(TF&& f, T&& x)
-> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)))
{
return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x));
}
を、私たちは、引数を結合する再帰helper
が必要x
複数TN
回:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x))
{
return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(f(x))
{
return f(x);
}
};
最後に、私たちは素敵なインターフェースを提供することができます
template <std::size_t TN, typename TF, typename T>
auto call_with_same_arg(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)))
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
使用法:
int add(int a, int b, int c)
{
return a + b + c;
}
int main()
{
assert(call_with_same_arg<3>(add, 5) == 15);
}
は、ここで同じことの完全なC++ 17の実装です:
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
if constexpr(TN == 1)
{
return f(x);
}
else
{
return call_with_same_arg<TN - 1>(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
}
完全のために
、C++ 14の実装:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return helper<TN - 1>{}(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return f(x);
}
};
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
は答えをいただき、ありがとうございます。あなたが他のC++標準のための解決策を考えているなら、ここでそれらを書くことが自由になります。私はちょうど(そしてそれは)テンプレートメタプログラミングのトリックであることを示すために、C++ 11を書きました。 –
おお、あなたはちょうどC++ 17バージョンを投稿しました。 C++のためのものと同じものがありますか? –
@ YaroslavKishchenko:少し長くなりますが、C++よりも優れています。それを秒間に投稿します。 –