作为日志库的一部分,我希望能够迭代参数包,将每个值写入流。然而,我的第一次尝试并没有编译。第一个错误是"错误C2144:语法错误:' int'之前应该有'}'"。
#include <sstream>
#include <ostream>
#include <iomanip>
#include <fstream>
template <typename ...Args>
std::ostream & Write(std::ostream & o, std::initializer_list<Args...> list)
{
size_t size = list.size();
if(list.size() > 0)
{
for(size_t i = 0; i < (size - 1); i++)
o << list[i] << ", ";
o << list[i];
}
return o;
}
template<typename ...Args>
std::ostream & Write(std::ostream & o, Args...)
{
return Write(o, { Args... });
}
int main(int argc, wchar_t * argv[])
{
std::ostringstream o;
Write(o, 1, "Hello", 2, "World", 3, 1.4857);
// o should contain the string of characters "1, Hello, 2, World, 3, 1.4857"
return 0;
}
如何迭代...中的每个项目并将其发送到流?
答案 0 :(得分:7)
递归是一种选择:
template<typename Arg>
std::ostream & Write(std::ostream & o, Arg&& arg) {
return o << std::forward<Arg>(arg);
}
template<typename Arg, typename ...Args>
std::ostream & Write(std::ostream & o, Arg&& arg, Args&&... args)
{
o << std::forward<Arg>(arg) << ", ";
return Write(o, std::forward<Args>(args)...);
}
或者,包扩展技巧仍然有效,稍微调整一下 - 你需要特殊情况下列表中的第一项:
template<typename Arg, typename ...Args>
std::ostream & Write(std::ostream & o, Arg&& arg, Args&&... args)
{
o << std::forward<Arg>(arg);
using expander = int[];
(void) expander{ (o << ", " << std::forward<Args>(args), void(), 0)... };
return o;
}
答案 1 :(得分:2)
如果最后一个额外的逗号可以,请使用
template<typename... Args>
std::ostream& Write(std::ostream& o, Args&&... args)
{
std::initializer_list<bool> { o << std::forward<Args>(args) << ", "... };
return o;
}
否则你需要递归:
template <typename A>
std::ostream& Write(std::ostream& o, A&& a)
{ return o << std::forward<A>(a); }
template <typename A, typename... Args>
std::ostream& Write(std::ostream& o, A&& a, Args&&... args)
{
return Write(o << std::forward<A>(a) << ", ", std::forward<Args>(args)...);
}
答案 2 :(得分:2)
这是我喜欢使用的实用程序:
#define VARIADIC_DETAIL_CAT2(a, b) a ## b
#define VARIADIC_DETAIL_CAT(a, b) VARIADIC_DETAIL_CAT2(a, b)
#define VARIADIC_EXPAND(...) \
int VARIADIC_DETAIL_CAT(libutil_expando, __COUNTER__) [] = { 0, \
((__VA_ARGS__), 0)... \
} \
/**/
有了这个,你可以写:
template<typename... Args>
std::ostream & Write(std::ostream& o, Args&&... args)
{
VARIADIC_EXPAND(o << std::forward<Args>(args));
}
获得正确的分隔符非常棘手。
答案 3 :(得分:0)
可以编写一个辅助函数来遍历参数包:
// Invoke each of the functions `f` in sequence
template<typename... F>
void invoke_all(F&&... f) {
std::initializer_list<bool>{(f(), false)...};
}
根据您的情况,可以用作:
template<typename... Args>
std::ostream& Write(std::ostream& os, Args&&... args) {
auto joiner = std::experimental::ostream_joiner(os, ", ");
invoke_all([&]() {
*joiner++ = std::forward<Args>(args);
}...);
}