7

SOの質問「タプルを反復する」への回答を使用 して、オーバーロードするメソッドを記述しました<<g++ 4.7この方法はテスト済みで、Debian スクイーズで正しく動作するようです。

<<ただし、このメソッドは明示的にインスタンス化できないよう に見えるため、一種の回り道です(私はそれについての投稿を見つけましたhere )。そのため、文字列メソッドを定義してから呼び出す必要があります。ベクトルについても同様の方法がありますが、これはより直接的です。同じアプローチを使用して、または別の方法で文字列メソッドを作成する余分な手順を排除する方法について、誰か提案がありますか? 前もって感謝します。

#include <tuple>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using std::ostream;
using std::cout;
using std::endl;
using std::vector;
using std::string;

// Print vector<T>.
template<typename T> ostream& operator <<(ostream& out, const vector<T> & vec)
{
  unsigned int i;
  out << "[";
  for(i=0; i<vec.size(); i++)
    {
      out << vec[i];
      if(i < vec.size() - 1)
    out << ", ";
    }
  out << "]";
  return out;
}

////////////////////////////////////////////////////////////////

// Print tuple.
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), string>::type
stringval(const std::tuple<Tp...> & t)
{
  std::stringstream buffer;
  buffer << "]";
  return buffer.str();
}

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), string>::type
stringval(const std::tuple<Tp...> & t)
{
  std::stringstream buffer;
  size_t len = sizeof...(Tp);
  if(I==0)
      buffer << "[";
  buffer << std::get<I>(t);
  if(I < len - 1)
    buffer << ", ";
  buffer << stringval<I + 1, Tp...>(t);
  return buffer.str();
}

template<typename... Tp> ostream& operator <<(ostream& out, const std::tuple<Tp...> & t)
{
  out << stringval(t);
  return out;
}

int
main()
{
  typedef std::tuple<int, float, double> T;
  std::tuple<int, float, double> t = std::make_tuple(2, 3.14159F, 2345.678);
  cout << t << endl;
}

コンパイルすると、これは

[2, 3.14159, 2345.68]
4

5 に答える 5

5

std::ostream&をそのstringval関数に渡して、のout <<代わりに使用できますbuffer <<

デモ:

#include <tuple>
#include <iostream>
#include <type_traits>

template <size_t n, typename... T>
typename std::enable_if<(n >= sizeof...(T))>::type
    print_tuple(std::ostream&, const std::tuple<T...>&)
{}

template <size_t n, typename... T>
typename std::enable_if<(n < sizeof...(T))>::type
    print_tuple(std::ostream& os, const std::tuple<T...>& tup)
{
    if (n != 0)
        os << ", ";
    os << std::get<n>(tup);
    print_tuple<n+1>(os, tup);
}

template <typename... T>
std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& tup)
{
    os << "[";
    print_tuple<0>(os, tup);
    return os << "]";
}
于 2012-02-12T10:40:13.720 に答える
1

おそらく、非再帰的 (実際には再帰的ですが、より自然な方法で) ソリューションを実現するために C++17 (まだリリースされていません) は必要ありません。つまり、フォールド式は必要なく、インデックス シーケンス (C++14) とテンプレート パラメーター パック (C++11) のみが必要です。

#include <iostream>
#include <sstream>
#include <utility>
#include <tuple>
#include <string>

template<class T>
std::ostringstream& concat_to_stream(std::ostringstream &oss, T &&arg) {
  oss << arg;
  return oss;
}

template<class First, class ...Rest>
std::ostringstream& concat_to_stream(std::ostringstream &oss, First &&firstArg, Rest &&... restArgs) {
  oss << firstArg << ", ";
  return concat_to_stream(oss, std::forward<Rest &&>(restArgs)...);
}

template<class ...Types>
std::string concat_to_string(Types &&... args) {
  std::ostringstream oss;
  oss << '[';
  concat_to_stream(oss, std::forward<Types &&>(args)...);
  oss << ']';
  return oss.str();
}

template<class Tuple, size_t... Indices>
std::string help_concat(const Tuple &tuple, std::index_sequence<Indices...>) {
  return concat_to_string(std::get<Indices>(tuple)...);
};

template<class ...Types>
std::string tuple_to_string(const std::tuple<Types...> &tuple) {
  return help_concat(tuple, std::make_index_sequence<sizeof...(Types)>{});
};

template<class ...Types>
std::ostream &operator<<(std::ostream &os, const std::tuple<Types...> &tuple) {
  return os << tuple_to_string(tuple);
}

int main() {
  std::tuple<int, double, std::string> sample_tuple = std::make_tuple(3, 1.723, "Hi!");
  std::cout << sample_tuple << '\n'; // [3, 1.723, Hi!]
  return 0;
}

再帰部分は、concat_to_streamかなり自然で一般的な部分です。重要な部分は ですhelp_concat。これは、Implementing std::tuple From The Ground Up: Part 6, tuple_cat Take 1 から学びました。

この手法は、パラメーター リストでダミーを使用してテンプレート パラメーターstd::index_sequenceリストを推測することで、関数が受け入れることができる可変引数リストにsize_t... Indices内容を "フラット化"できるようにします。std::tupleconcat_to_string

于 2016-04-20T22:34:06.557 に答える
0

これは、std::integer_sequence およびその他の関連手法を使用した非再帰バージョンです。

template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_tuple_impl(std::basic_ostream<Ch,Tr>& os,
                      const Tuple& t,
                      std::index_sequence<Is...>)
{
    using swallow = int[];
    (void)swallow{0, (void(os << (Is == 0? "" : ", ") << std::get<Is>(t)), 0)...};
}

template<class Ch, class Tr, class... Args>
decltype(auto) operator<<(std::basic_ostream<Ch, Tr>& os,
                          const std::tuple<Args...>& t)
{
    os << "(";
    print_tuple_impl(os, t, std::index_sequence_for<Args...>{});
    return os << ")";
}

もともとはここからです: http://en.cppreference.com/w/cpp/utility/integer_sequence

于 2016-09-06T15:47:24.200 に答える