我有一个类,让我们用可变参数模板参数调用它Sample
。该类包含函数run(Args... args)
。该类还实现了一个调用此函数的流操作符。
该课程如下:
template<typename ...Args>
class Sample
{
void run(Args... args)
{
// do something
}
Sample& operator<<(const tuple<Args...>& args)
{
run(unpack_somehow(args)...);
return *this;
}
};
现在我想使用stream运算符来连接多个调用,方法是通过元组的大括号初始化传递参数:
void main()
{
Sample<int, string, int> s;
// doesn't work :(
s << {1, "msg", 2} << {1, "msg", 2};
}
我知道我可以写make_tuple(1, "msg", 2)
并且它会起作用,但我正在寻找一个不需要额外函数调用的解决方案,例如make_tuple
。
有没有办法实现这样一个功能,我可以在大括号中传递参数(或者通过重载逗号运算符可以通过逗号分隔)?
答案 0 :(得分:2)
当您使用第s << {1, "msg", 2} << {1, "msg", 2};
行时,它不会为C ++编译器提供足够的信息来推断出这些初始值设定项列表的含义。
除非你给编译器提示(使用make_tuple
或传递实际的tuple
变量),否则它不会知道你的意思,也无法调用相应的{{1 }}
看起来你运气不好。这不能以您的问题发布方式完成。
答案 1 :(得分:2)
初始化程序列表未在操作员一侧启用。
它们未在右侧启用,因为它们未在左侧启用,并且它们未在左侧启用,因为这对解析器构成了太大的挑战。
至于的原因,来自2007年的Stroustrup和Dos Reis的draft/discussion paper N2215提供了很多关于各种上下文中初始化列表的问题的深入见解。具体来说,有一个关于二元运算符的部分(第6.2节):
考虑初始化列表的更多常规用法。例如:
v = v+{3,4}; v = {6,7}+v;
当我们将运算符视为函数的语法糖时,我们自然会认为上述等价于
v = operator+(v,{3,4}); v = operator+({6,7},v);
因此,将初始化列表的使用扩展到表达式是很自然的。初始化列表与运算符结合使用是一种“自然”符号 但是,编写允许任意使用初始化列表的LR(1)语法并非易事。一个块也以{开始允许初始化列表,因为表达式的第一个(最左边)实体会导致语法混乱。
允许初始化器列表作为二进制运算符的右侧操作数,这是微不足道的 下标和语法的类似孤立部分。真正的问题是允许;a={1,2}+b;
作为赋值语句而不允许;{1,2}+b;
。我们怀疑允许初始化列表作为右手,但也不是[原文如此]作为大多数运算符的左手参数太多了,[...]