pretty-print std :: tuple [英] Pretty-print std::tuple

查看:185
本文介绍了pretty-print std :: tuple的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我对漂亮打印STL容器的上一个问题的跟进。






在下一个步骤中,我想要包括漂亮打印 std :: tuple< Args ...> ,使用可变参数模板(因此这是严格的C ++ 11)。对于 std :: pair< S,T> ,我只需说

  std :: ostream& operator<<<<(std :: ostream& o,const std :: pair< S,T& p)
{
return o& (<<< p.first<<,<< p.second<<);
}

打印元组的类似结构是什么?



我尝试了各种模板参数堆栈解包,传递索引并使用SFINAE来发现我在最后一个元素,但没有成功。我不会用我破碎的代码给你负担;问题描述有希望直截了当。基本上,我想要以下行为:

  auto a = std :: make_tuple(5,Hello,-0.1 ); 
std :: cout<< a<< std :: endl; // prints:(5,Hello,-0.1)

Yay,指南

  namespace aux { 
template< std :: size_t ...> struct seq {};

template< std :: size_t N,std :: size_t ... Is>
struct gen_seq:gen_seq< N-1,N-1,Is ...> {};

template< std :: size_t ... Is>
struct gen_seq< 0,Is ...> :seq< Is ...> {};

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

template< class Ch,class Tr,class ... Args>
auto operator<<<(std :: basic_ostream< Ch,Tr>& os,std :: tuple< Args ...> const& t)
- > std :: basic_ostream< Ch,Tr>&
{
os<< ;
aux :: print_tuple(os,t,aux :: gen_seq< sizeof ...(Args)>());
return os&
}






对于分隔符内容,只需添加以下部分特殊化:

  // tuple的分隔符
template< class ... Args>
struct delimiters< std :: tuple< Args ...>,char> {
static const delimiters_values< char>值;
};

template< class ... Args>
const delimiters_values< char>分隔符< std :: tuple< Args ...>,char> :: values = {(,,,)};

template< class ... Args>
struct delimiters< std :: tuple< Args ...>,wchar_t> {
static const delimiters_values< wchar_t>值;
};

template< class ... Args>
const delimiters_values< wchar_t> delimiters< std :: tuple< Args ...>,wchar_t> :: values = {L(,L,,L)};

并更改运算符<< print_tuple 因此:

  template< class Ch,class Tr,class。 Args> 
auto operator<<<(std :: basic_ostream< Ch,Tr>& os,std :: tuple< Args ...> const& t)
- > std :: basic_ostream< Ch,Tr>&
{
typedef std :: tuple< Args ...> tuple_t;
if(delimiters< tuple_t,Ch> :: values.prefix!= 0)
os<分隔符< tuple_t,char> :: values.prefix;

print_tuple(os,t,aux :: gen_seq< sizeof ...(Args)>());

if(delimiters< tuple_t,Ch> :: values.postfix!= 0)
os< delimiters< tuple_t,char> :: values.postfix;

return os;
}

  template< class Ch,class Tr,class Tuple,std :: size_t ... Is> 
void print_tuple(std :: basic_ostream< Ch,Tr>& os,Tuple const& t,seq< Is ...>){
using swallow = int [];
char const * delim = delimiters< Tuple,Ch> :: values.delimiter;
if(!delim)delim =;
(void)swallow {0,(void(os<<(is == 0?:delim)<< std :: get< Is>(t)),0) 。};
}


This is a follow-up to my previous question on pretty-printing STL containers, for which we managed to develop a very elegant and fully general solution.


In this next step, I would like to include pretty-printing for std::tuple<Args...>, using variadic templates (so this is strictly C++11). For std::pair<S,T>, I simply say

std::ostream & operator<<(std::ostream & o, const std::pair<S,T> & p)
{
  return o << "(" << p.first << ", " << p.second << ")";
}

What is the analogous construction for printing a tuple?

I've tried various bits of template argument stack unpacking, passing indices around and using SFINAE to discover when I'm at the last element, but with no success. I shan't burden you with my broken code; the problem description is hopefully straight-forward enough. Essentially, I'd like the following behaviour:

auto a = std::make_tuple(5, "Hello", -0.1);
std::cout << a << std::endl; // prints: (5, "Hello", -0.1)

Bonus points for including the same level of generality (char/wchar_t, pair delimiters) as the the previous question!

解决方案

Yay, indices~

namespace aux{
template<std::size_t...> struct seq{};

template<std::size_t N, std::size_t... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};

template<std::size_t... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

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

template<class Ch, class Tr, class... Args>
auto operator<<(std::basic_ostream<Ch, Tr>& os, std::tuple<Args...> const& t)
    -> std::basic_ostream<Ch, Tr>&
{
  os << "(";
  aux::print_tuple(os, t, aux::gen_seq<sizeof...(Args)>());
  return os << ")";
}

Live example on Ideone.


For the delimiter stuff, just add these partial specializations:

// Delimiters for tuple
template<class... Args>
struct delimiters<std::tuple<Args...>, char> {
  static const delimiters_values<char> values;
};

template<class... Args>
const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };

template<class... Args>
struct delimiters<std::tuple<Args...>, wchar_t> {
  static const delimiters_values<wchar_t> values;
};

template<class... Args>
const delimiters_values<wchar_t> delimiters<std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };

and change the operator<< and print_tuple accordingly:

template<class Ch, class Tr, class... Args>
auto operator<<(std::basic_ostream<Ch, Tr>& os, std::tuple<Args...> const& t)
    -> std::basic_ostream<Ch, Tr>&
{
  typedef std::tuple<Args...> tuple_t;
  if(delimiters<tuple_t, Ch>::values.prefix != 0)
    os << delimiters<tuple_t,char>::values.prefix;

  print_tuple(os, t, aux::gen_seq<sizeof...(Args)>());

  if(delimiters<tuple_t, Ch>::values.postfix != 0)
    os << delimiters<tuple_t,char>::values.postfix;

  return os;
}

And

template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_tuple(std::basic_ostream<Ch, Tr>& os, Tuple const& t, seq<Is...>){
  using swallow = int[];
  char const* delim = delimiters<Tuple, Ch>::values.delimiter;
  if(!delim) delim = "";
  (void)swallow{0, (void(os << (Is == 0? "" : delim) << std::get<Is>(t)), 0)...};
}

这篇关于pretty-print std :: tuple的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆