namespace notstd {
template<std::size_t...Is>
struct index_sequence {};
template<std::size_t N, std::size_t...Is>
struct make_index_sequence:make_index_sequence<N-1,N-1,Is...>{};
template<std::size_t...Is>
struct make_index_sequence<0,Is...>:index_sequence<Is...>{};
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
namespace details {
template<class F, class Tuple, std::size_t...Is>
auto apply(F&& f, Tuple&& tuple, index_sequence<Is...>)
RETURNS(std::forward<F>(f)(std::get<Is>(std::forward<Tuple>(tuple))...))
template<class Tuple>
using raw_tuple = typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type;
template<class Tuple>
using tuple_count = std::tuple_size< raw_tuple<Tuple> >;
}
template<class F, class Tuple>
auto apply(F&& f, Tuple&& tuple)
RETURNS(
::notstd::details::apply(
std::forward<F>(f),
std::forward<Tuple>(tuple),
::notstd::make_index_sequence<
::notstd::details::tuple_count<Tuple>::value
>{}
)
)
}
を今、この::notstd::apply
はC++ 17のstd::apply
のように多くのことを振る舞います。
私たちは、あなたのToString
ToStream
経由にこれをのり:これも再帰的タプルを平ら
struct to_stream_t;
template<class...Args>
void ToStream(std::ostream& os, const std::tuple<Args...>& t) {
os << '{';
::notstd::apply(to_stream_t{os}, t);
os << '}';
}
inline void ToStream(std::ostream&) {}
template<class T>
void ToStream(std::ostream& os, const T& t) {
os << t;
}
template<class T0, class... Ts>
void ToStream(std::ostream& os, const T0& t0, const Ts& ... ts) {
ToStream(os, t0);
using discard=int[];
(void)discard{0,((
void(os << ' '), to_stream_t{os}(ts)
),0)...};
}
struct to_stream_t {
std::ostream& os;
template<class...Args>
void operator()(Args const&...args) const {
ToStream(os, args...);
}
};
template<class...Ts>
std::string ToString(Ts const&... ts) {
std::stringstream ss;
ToStream(ss, ts...);
return ss.str();
}
。
あなたがstd
以上または基本的なタイプのマニュアルToStream
実装を追加する場合は、to_stream_t
または再帰の前に体が動作しませんそれらを置きます。そして通常ToStream(os, t)
の代わりにto_stream_t{os}(t)
を経由して再帰するので、適切なオーバーロードを見つけることができます。
テストコード:
std::tuple<std::string, std::string, int> t("hello", "world", 42);
std::cout << ToString(t, "-", t);
Live example。
我々は、ベクターのサポートを強化することができます。その後、
template<class T, class A>
void ToStream(std::ostream& os, const std::vector<T, A>& v) {
os << '[';
for (auto const& x:v)
{
if (std::addressof(x) != v.data())
os << ',';
to_stream_t{os}(x);
}
os << ']';
}
このすべてでテスト:
std::tuple<std::string, std::string, int> t("hello", "world", 42);
std::cout << ToString(t, "-", t) << "\n";
std::vector<int> v {1,2,3};
std::cout << ToString(v) << "\n";
std::vector< std::tuple<int, int> > v2 {{1,2},{3,4}};
std::cout << ToString(v2) << "\n";
auto t2 = std::tie(v, v2);
std::cout << ToString(t2) << "\n";
Live example。
エンド出力は、次のとおり
{hello world 42} - {hello world 42}
[1,2,3]
[{1 2},{3 4}]
{[1,2,3] [{1 2},{3 4}]}
予想通り。あなたが
をあきらめ、この
#include<iostream>
#include<tuple>
#include<utility>
#include<sstream>
template<size_t... I>
struct index_sequence {};
template<size_t N, size_t sz, size_t... I>
struct make_index_sequence_
{
using type = typename make_index_sequence_<N, sz + 1, I..., sz>::type;
};
template<size_t N, size_t... I>
struct make_index_sequence_<N, N, I...>
{
using type = index_sequence<I...>;
};
template<size_t N>
using make_index_sequence = typename make_index_sequence_<N, 0>::type;
template<typename Fn, typename Tuple, size_t... I>
auto apply_(Fn&& fn, Tuple&& tup, index_sequence<I...>) -> decltype(fn(std::get<I>(tup)...))
{
return fn(std::get<I>(tup)...);
}
template<typename Fn, typename Tuple>
auto apply(Fn&& fn, Tuple&& tup) -> decltype(apply_(std::forward<Fn>(fn), std::forward<Tuple>(tup), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>{}))
{
return apply_(std::forward<Fn>(fn), std::forward<Tuple>(tup), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>{});
}
に上記のすべてのものをやってみたいことがC++ 11では
テンプレートは*コンパイル時のみ*です。ランタイム変数をテンプレート引数として使用することはできません。これを解決するには、パラメータパックを受け取るヘルパー関数を用意し、[タプルを展開する]ことをお勧めします(https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching -function-pointer)をヘルパー関数の呼び出しで使用します。 –
テンプレートメタプログラミングでは、反復は通常、再帰を使用して行われます。 –
私はC++のテンプレートが良くないので、コードを正確に記述する方法がわかりません...コードを表示しますか? – linrongbin