如何在c++11中将值输出到流的元组
How to output values to a tuple of streams in c++11
我正在尝试编写一个流运算符<<
,它可以输出到流的std::tuple
,而不是一个流。因此,基本上,我正在尝试用c++编写Unix tee
命令,并执行:
std::tie(std::cout,std::clog) << 1;
我尝试在c++11中使用可变模板编程递归地编写流运算符。到目前为止,我所拥有的是下面的代码。但是代码没有编译,并且错误消息相当长。
我的问题是,如何修复代码使其工作?
使用g++ -std=c++11
(gcc-4.8.1(编译的第一条错误消息是:
test.cpp:24:33: error: no match for 'operator<<' (operand types are 'std::tuple<std::basic_ostream<char, std::char_traits<char> >&, std::basic_ostream<char, std::char_traits<char> >&>' and 'int')
std::tie(std::cout,std::cout) << 1;
附言:我搜索了SO,有一些关于写复合流对象的帖子。该代码涉及流和streambuf的许多内部结构。我在这里寻求的是一个简单/天真的解决方案,用十几行来完成类似的任务。
感谢
我的代码:
#include <iostream>
#include <tuple>
template<typename _Value, typename Head, typename ... Tail>
struct _tee_stream {
static std::tuple<Head,Tail...>& _print(std::tuple<Head,Tail...>& _s, const _Value& _t) {
return std::make_tuple(std::get<0>(_s) << _t ,_tee_stream<Tail...,_Value>::_print(_s,_t));
}
};
template<typename _Value>
struct _tee_stream<_Value, std::tuple<>> {
static std::tuple<>& _print(std::tuple<>& _s, const _Value& _t) {
return _s;
}
};
template< typename _Value, typename... _TElements>
std::tuple<_TElements...>& operator<<(std::tuple<_TElements...>& _s, const _Value& _t) {
return _tee_stream<_Value, std::tuple<_TElements...>>::_print(_s, _t);
};
int main() {
std::tie(std::cout,std::cout) << 1; //no compile
std::make_tuple(std::cout,std::cout) << 1; //no compile either
}
更新:以下是基于@KerrekSB的示例代码对我有效的方法:
#include <iostream>
#include <tuple>
#include <utility>
#include <fstream>
template <unsigned int N>
struct tee_stream
{
template <typename ...Args, typename T>
static std::tuple<Args...> & print(std::tuple<Args...> & t, T && x)
{
std::get<sizeof...(Args) - N>(t) << x;
tee_stream<N - 1>::print(t, std::forward<T>(x));
return t;
}
};
template <>
struct tee_stream<0>
{
template <typename ...Args, typename T>
static std::tuple<Args...> & print(std::tuple<Args...> &, T &&) {}
};
template <typename ...Args, typename T>
std::tuple<Args...> & operator<<(std::tuple<Args...> & t, T && x)
{
return tee_stream<sizeof...(Args)>::print(t, std::forward<T>(x));
}
template <typename ...Args, typename T>
std::tuple<Args...> & operator<<(std::tuple<Args...> && t, T && x)
{
return tee_stream<sizeof...(Args)>::print(t, std::forward<T>(x));
}
int main()
{
std::ofstream os("a.txt");
auto t = std::tie(std::cout, os);
t << "Foo" << "Barn";
std::tie(std::cout, os) << "Foo" << "Barn";
}
http://ideone.com/fBXuvP
@Jarod42,
非常感谢。您的代码比我的原型更紧凑地执行递归/循环,并修复了代码中引用类型的使用。最初的测试用例如您的演示所示。然而,如果我在流中使用std::endl
(而不是"Foo"(或std::ofstream
(而不是std::cout
(,我仍然无法编译您的版本,如下"not OK"行所示。你知道怎么解决这些问题吗?
#include <iostream>
#include <fstream>
#include <tuple>
#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>
template <std::size_t...> 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<0u, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
namespace detail
{
template <typename Tuple, typename T, std::size_t...Is>
Tuple output(const Tuple& t, const T& x, index_sequence<Is...>) {
return Tuple{(std::get<Is>(t) << x)...};
}
}
template <typename ...Args, typename T>
std::tuple<Args&...> operator<<(const std::tuple<Args&...>& t, const T& x) {
return detail::output(t, x, make_index_sequence<sizeof...(Args)>());
}
int main() {
std::ofstream os("aa.txt");
os << "Hi" << std::endl;
std::tie(std::cout, std::cout) << "Foo" << "Bar"; //OK
std::tie(std::cout, std::cout) << "Foo" << "Bar" << std::endl; //not OK on endl
std::tie(std::cout, os) << 1 << "Foo" << "Bar"; //not OK on ofstream
return 0;
}
您可以使用以下内容:
#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>
template <std::size_t...> 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<0u, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
// Helper. C++11 cannot use: auto f() { return foo(); }
// Usage: auto f() -> Return(foo())
#define Return(ret) decltype(ret) { return ret; }
namespace detail
{
template <typename Tuple, typename T, std::size_t...Is>
auto output(const Tuple& t, const T& x, index_sequence<Is...>) ->
Return (std::tie(std::get<Is>(t) << x...))
}
template <typename ...Args, typename T>
auto operator<<(const std::tuple<Args&...>& t, const T& x) ->
Return(detail::output(t, x, make_index_sequence<sizeof...(Args)>()))
实例
一个问题在于参数:std::tuple<_TElements...>& _s
由于您试图将operator <<
与std::tie
和std::make_tuple
返回的临时值一起使用,因此会出现编译器错误,因为无法将临时值绑定到引用。
不过,常量引用(std::tuple<_TElements...> const& _s
(也可以
(你也可以使用右值参考(
不要使用以下划线开头的名称(_
(;这些是留给实施的。
- C++:TypeDef使用元组
- Pybind11:将元组列表从Python传递到C++
- 重载元组索引运算符-C++
- 在C++中,如何通过几种类型从元组中选择多个元素
- 将fold表达式与std::一起用于两个元组
- std::ranges::elements_view,用于自定义类似元组的数据
- 将元组的向量转换/构造为堆
- 专用于 std 元组的模板,而无需用户执行remove_cvref
- 将元组的向量构造成堆
- 元组由 Swig 生成的 Python 包装器返回,用于C++向量
- 将元组类型扩展为可变参数模板?
- 时间复杂度 当具有复合数据类型(如元组或对)时?
- 类内部和外部静态 constexpr 元组之间的差异
- 可变参数模板与使用元组在参数中添加不同的数据对
- 访问和打印元组中的数据,并使用 C++14 使用模板函数显示数据
- boost::包含提升单元的元组的哈希值
- 我正在寻找一种优雅的方式来从元组向量创建tuple_element向量
- 如何在可变参数模板函数中遍历可变参数元组?
- 过载输出<<用于类的运算符,以打印其中的元组
- 如何在c++11中将值输出到流的元组