重载运算符 <<对于 std::tuple - 可能的简化?
我使用对SO问题“迭代元组”的答案来编写一个方法来重载<<
。此方法经过测试,似乎可以在 Debian squeeze 上的 g++ 4.7
上正常工作。
然而,这种方法有点迂回,因为似乎 <<
无法显式实例化(我找到了一篇关于它的文章
此处)。因此,人们被迫定义一个字符串方法,然后调用它。我对向量也有类似的方法,更直接。有人对如何使用相同的方法或其他方式消除创建字符串方法的额外步骤有建议吗?提前致谢。
#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]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您只需将
std::ostream&
传递到stringval
函数中,并使用out <<
而不是buffer
<。
演示:
You can just pass the
std::ostream&
into thatstringval
function and useout <<
instead ofbuffer <<
.Demo:
基于折叠表达式 (C++17)、索引序列 (C++14)、lambda 函数和模板参数包(均为 C++11)的非递归 C++17 方式解决方案):
直播演示
Non-recursive C++17-way solution based on fold expressions (C++17), index sequences (C++14), lambda-functions and template parameter packs (both C++11):
LIVE DEMO
C++17 解决方案。
必须将其放入命名空间 std 中才能使 ADL 正常工作。
事实上每个运算符<<对于命名空间 N 中的类型,应该在命名空间 N 中定义。在这种情况下,ADL 将导致编译器
找到它。
需要标头
在线示例此处。
C++17 solution.
This has to be put in namespace std in order for ADL to work.
In fact every operator<< for a type in namespace N should be defined in namespace N. In that case ADL will cause the compiler
to find it.
Needs headers
Online example here.
也许您不需要 C++17(尚未发布)来获得非递归(实际上是递归的,但以更自然的方式)解决方案。即,您不需要折叠表达式,只需要索引序列(C++14)和模板参数包(C++11)。
递归部分是 concat_to_stream 部分,这是非常自然和常见的。关键部分是
help_concat
,我从 从头开始实现 std::tuple:第 6 部分,tuple_cat 取 1。该技术是在参数列表中使用虚拟
std::index_sequence
来推导模板参数列表中的size_t... Indices
,从而允许我们“扁平化”内容将std::tuple
转换为可变参数列表,该列表可以被concat_to_string
函数接受。Probably you don't need C++17 (which is not yet released) to attain a non-recursive (actually recursive, but in a more natural way) solution. I.e., you don't need fold expressions, and only need index sequences (C++14) and template parameter packs (C++11).
The recursive part is the
concat_to_stream
part, which is pretty natural and common. The key part ishelp_concat
, which I learn from Implementing std::tuple From The Ground Up: Part 6, tuple_cat Take 1.The technique is to use an dummy
std::index_sequence
in the parameter list to deducesize_t... Indices
in the template parameter list, allowing us to "flat" the contents ofstd::tuple
into a variadic parameter list, which can be accepted by theconcat_to_string
function.这是一个非递归版本,使用 std::integer_sequence 和其他一些相关技术。
最初它来自这里:
http://en.cppreference.com/w/cpp/utility/integer_sequence
Here is a non-recursive version, by using std::integer_sequence and some other related techniques.
originally it's from here:
http://en.cppreference.com/w/cpp/utility/integer_sequence
有一个巧妙的技巧可以让您将元组的所有元素作为单独的变量获取。这允许你这样写:
There is a neat trick that allows you to get all the elements of a tuple as individual variables. This allows you to write it like this: