1

我有一个类,让我们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;
    }
};

现在我想使用流运算符来连接多个调用,通过元组的大括号初始化传递参数:

void main()
{
    Sample<int, string, int> s;

    // doesn't work :(
    s << {1, "msg", 2} << {1, "msg", 2};
}

我知道我可以只写make_tuple(1, "msg", 2)并且它会工作,但我正在寻找一种不需要额外函数调用的解决方案,例如make_tuple.

有没有办法实现这样一个功能,我可以在大括号中传递参数(或者通过重载逗号运算符通过逗号分隔)?

4

2 回答 2

2

当您使用该行时s << {1, "msg", 2} << {1, "msg", 2};,它不会为 C++ 编译器提供足够的信息来推断这些初始值设定项列表的含义。

除非您向编译器提示(使用 amake_tuple或传递实际tuple变量),否则它不会知道您的意思,也无法调用适当的operator<<().

看来你运气不好。这不能以您发布问题的方式完成。

于 2017-02-16T15:40:48.227 回答
2

初始化器列表未在操作员一侧启用。

它们未在右侧启用,因为它们未在左侧启用,并且它们未在左侧启用,因为这会对解析器构成太大的挑战。

至于造成这种情况的原因, Stroustrup 和 Dos Reis 从 2007 年开始的草稿/讨论论文 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;. 我们怀疑允许初始化列表作为右手参数,但不允许 [原文如此] 作为大多数运算符的左手参数,这太过分了,[...]

于 2017-02-16T18:40:16.927 回答