何时重载逗号运算符?

发布于 2024-10-31 04:17:45 字数 196 浏览 1 评论 0 原文

我经常看到关于在 C++ 中重载逗号运算符的问题(主要与重载本身无关,但与序列点的概念类似),这让我想知道:

什么时候你应该重载逗号?其实际用途有哪些例子?

我只是想不出任何我

foo, bar;

在现实世界代码中见过或需要的例子,所以我很好奇什么时候(如果有的话)实际使用它。

I see questions on SO every so often about overloading the comma operator in C++ (mainly unrelated to the overloading itself, but things like the notion of sequence points), and it makes me wonder:

When should you overload the comma? What are some examples of its practical uses?

I just can't think of any examples off the top of my head where I've seen or needed to something like

foo, bar;

in real-world code, so I'm curious as to when (if ever) this is actually used.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

向地狱狂奔 2024-11-07 04:17:45

我使用逗号运算符来索引具有多个索引的映射。

enum Place {new_york, washington, ...};

pair<Place, Place> operator , (Place p1, Place p2)
{
    return make_pair(p1, p2);
}

map< pair<Place, Place>, double> distance;

distance[new_york, washington] = 100;
弃用通知
在 C++20 中不推荐使用在数组下标中不包含括号的逗号运算符,并在 C++23 中删除。
请参阅 有关逗号运算符的 cpp 参考文章

I have used the comma operator in order to index maps with multiple indices.

enum Place {new_york, washington, ...};

pair<Place, Place> operator , (Place p1, Place p2)
{
    return make_pair(p1, p2);
}

map< pair<Place, Place>, double> distance;

distance[new_york, washington] = 100;
Deprecation Notice
Use of the comma operator without enclosing parentheses in an array subscript was deprecated in C++20 and removed in C++23.
See the cppreference article on the comma operator.
墟烟 2024-11-07 04:17:45

让我们稍微改变一下重点:

什么时候应该重载逗号?

答案是:从来没有。

例外:如果您正在进行模板元编程,操作符在操作符优先级列表的最底部有一个特殊的位置,它可以在构造 SFINAE-guards 等时派上用场。

唯一的两个我见过的重载operator,的实际用途都在Boost中:

Let's change the emphasis a bit to:

When should you overload the comma?

The answer: Never.

The exception: If you're doing template metaprogramming, operator, has a special place at the very bottom of the operator precedence list, which can come in handy for constructing SFINAE-guards, etc.

The only two practical uses I've seen of overloading operator, are both in Boost:

草莓味的萝莉 2024-11-07 04:17:45

Boost.Assign 使用它,让您做这样的事情:

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;

我已经看到它用于奇怪的语言黑客,我会看看是否能找到一些。


啊哈,我确实记得其中一个奇怪的用途:收集多个表达式。 (警告,黑魔法。)

Boost.Assign uses it, to let you do things like:

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;

And I've seen it used for quirky language hacks, I'll see if I can find some.


Aha, I do remember one of those quirky uses: collecting multiple expressions. (Warning, dark magic.)

童话里做英雄 2024-11-07 04:17:45

逗号有一个有趣的属性,它可以采用 void 类型的参数。如果是这种情况,则使用内置逗号运算符。

当您想要确定表达式是否具有 void 类型时,这很方便:

namespace detail_
{
    template <typename T>
    struct tag
    {
        static T get();
    };

    template <typename T, typename U>
    tag<char(&)[2]> operator,(T, tag<U>);

    template <typename T, typename U>
    tag<U> operator,(tag<T>, tag<U>);
}

#define HAS_VOID_TYPE(expr) \
    (sizeof((::detail_::tag<int>(), \
             (expr), \
             ::detail_::tag<char>).get()) == 1)

我让读者作为练习弄清楚发生了什么。请记住,运算符 与右侧关联。

The comma has an interesting property in that it can take a parameter of type void. If it is the case, then the built-in comma operator is used.

This is handy when you want to determine if an expression has type void:

namespace detail_
{
    template <typename T>
    struct tag
    {
        static T get();
    };

    template <typename T, typename U>
    tag<char(&)[2]> operator,(T, tag<U>);

    template <typename T, typename U>
    tag<U> operator,(tag<T>, tag<U>);
}

#define HAS_VOID_TYPE(expr) \
    (sizeof((::detail_::tag<int>(), \
             (expr), \
             ::detail_::tag<char>).get()) == 1)

I let the reader figure out as an exercise what is going on. Remember that operator, associates to the right.

姐不稀罕 2024-11-07 04:17:45

类似于 @GMan 的 Boost.Assign 示例,Blitz++ 重载逗号运算符以提供 用于处理多维数组的便捷语法。例如:

Array<double,2> y(4,4);   // A 4x4 array of double
y = 1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1;

Similar to @GMan's Boost.Assign example, Blitz++ overloads the comma operator to provide a convenient syntax for working with multidimensional arrays. For example:

Array<double,2> y(4,4);   // A 4x4 array of double
y = 1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1;
じ违心 2024-11-07 04:17:45

我使用逗号运算符来打印日志输出。它实际上与 ostream::operator<< 非常相似,但我发现逗号运算符实际上更好更适合该任务。

所以我有:

template <typename T>
MyLogType::operator,(const T& data) { /* do the same thing as with ostream::operator<<*/ }

它有这些很好的属性

  • 逗号运算符的优先级最低。因此,如果您想流式传输表达式,即使您忘记了括号,事情也不会混乱。比较:

    myLog << “掩码结果是:” << x&y; // 运算符优先级会搞乱这一点
    myLog, "结果是:", x&y;
    

    您甚至可以毫无问题地在内部混合比较运算符,例如

    myLog, "a==b: ", a==b;
    
  • 逗号运算符在视觉上很小。将许多东西粘在一起时不会扰乱阅读

    myLog, "Coords=", g, ':', s, ':', p;
    
  • 它与逗号运算符的含义一致,即“打印这个”,然后“打印那个”。

I use the comma operator for printing log output. It actually is very similar to ostream::operator<< but I find the comma operator actually better for the task.

So I have:

template <typename T>
MyLogType::operator,(const T& data) { /* do the same thing as with ostream::operator<<*/ }

It has these nice properties

  • The comma operator has the lowest priority. So if you want to stream an expression, things do not mess up if you forget the parenthesis. Compare:

    myLog << "The mask result is: " << x&y; //operator precedence would mess this one up
    myLog, "The result is: ", x&y;
    

    you can even mix comparisons operators inside without a problem, e.g.

    myLog, "a==b: ", a==b;
    
  • The comma operator is visually small. It does not mess up with reading when gluing many things together

    myLog, "Coords=", g, ':', s, ':', p;
    
  • It aligns with the meaning of the comma operator, i.e. "print this" and then "print that".

自此以后,行同陌路 2024-11-07 04:17:45

SOCI - C++ 数据库访问库中,它用于实现接口的入站部分

sql << "select name, salary from persons where id = " << id,
       into(name), into(salary);

基本原理常见问题解答

问:重载逗号运算符只是混淆,我不喜欢它。

那么,请考虑以下因素:

“将查询 X 发送到服务器 Y 并将结果放入变量 Z 中。”

上面的“and”起到了逗号的作用。即使重载逗号运算符在 C++ 中并不是一种非常流行的做法,一些库也会这样做,从而实现简洁且易于学习的语法。我们非常确定在 SOCI 中逗号运算符被重载并具有良好的效果。

In SOCI - The C++ Database Access Library it is used for the implementation of the inbound part of the interface:

sql << "select name, salary from persons where id = " << id,
       into(name), into(salary);

From the rationale FAQ:

Q: Overloaded comma operator is just obfuscation, I don't like it.

Well, consider the following:

"Send the query X to the server Y and put result into variable Z."

Above, the "and" plays a role of the comma. Even if overloading the comma operator is not a very popular practice in C++, some libraries do this, achieving terse and easy to learn syntax. We are pretty sure that in SOCI the comma operator was overloaded with a good effect.

陌伤ぢ 2024-11-07 04:17:45

一种可能性是 Boost Assign 库(尽管我很确定有些人会认为这种滥用而不是很好的用途)。

Boost Spirit 可能也会重载逗号运算符(它几乎重载了其他所有内容......)

One possibility is the Boost Assign library (though I'm pretty sure some people would consider this abuse rather than a good use).

Boost Spirit probably overloads the comma operator as well (it overloads almost everything else...)

呆萌少年 2024-11-07 04:17:45

实际用途之一是在宏中有效地使用可变参数。顺便说一句,变量参数早期是 GCC 中的扩展,现在是 C++11 标准的一部分。

假设我们有一个类X,它将A类型的对象添加到其中。即

class X {
  public: X& operator+= (const A&);
};

如果我们想将 1 个或多个 A 对象添加到 X buffer; 中怎么办?
例如,

#define ADD(buffer, ...) buffer += __VA_ARGS__

上面的宏,如果用作:

ADD(buffer, objA1, objA2, objA3);

那么它将扩展为:

buffer += objA1, objeA2, objA3;

因此,这将是使用逗号运算符的完美示例,因为变量参数也以相同的方式扩展。

因此,为了解决这个问题,我们重载 comma 运算符并将其包裹在 += 周围,如下所示

  X& X::operator, (const A& a) {  // declared inside `class X`
    *this += a;  // calls `operator+=`
  }

One of the practical usage is for effectively using it with variable arguments in macro. By the way, variable arguments was earlier an extension in GCC and now a part of C++11 standard.

Suppose we have a class X, which adds object of type A into it. i.e.

class X {
  public: X& operator+= (const A&);
};

What if we want to add 1 or more objects of A into X buffer;?
For example,

#define ADD(buffer, ...) buffer += __VA_ARGS__

Above macro, if used as:

ADD(buffer, objA1, objA2, objA3);

then it will expand to:

buffer += objA1, objeA2, objA3;

Hence, this will be a perfect example of using comma operator, as the variable arguments expand with the same.

So to resolve this we overload comma operator and wrap it around += as below

  X& X::operator, (const A& a) {  // declared inside `class X`
    *this += a;  // calls `operator+=`
  }
权谋诡计 2024-11-07 04:17:45

同样,我收到了一个带有逗号运算符重载的 github pull 请求。 以下操作:

class Mylogger {
    public:
            template <typename T>
            Mylogger & operator,(const T & val) {
                    std::cout << val;
                    return * this;
            }
 };

 #define  Log(level,args...)  \
    do { Mylogger logv; logv,level, ":", ##args; } while (0)

在我的代码中我可以执行

 Log(2, "INFO: setting variable \", 1, "\"\n");

Along the same lines, I was sent a github pull request with comma operator overload. It looked something like following

class Mylogger {
    public:
            template <typename T>
            Mylogger & operator,(const T & val) {
                    std::cout << val;
                    return * this;
            }
 };

 #define  Log(level,args...)  \
    do { Mylogger logv; logv,level, ":", ##args; } while (0)

then in my code I can do:

 Log(2, "INFO: setting variable \", 1, "\"\n");
妳是的陽光 2024-11-07 04:17:45

以下是 OpenCV 文档中的示例(http://docs.opencv.org /modules/core/doc/basic_structs.html#mat)。逗号运算符用于 cv::Mat 初始化:

// create a 3x3 double-precision identity matrix
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);

Here is an example from OpenCV documentation (http://docs.opencv.org/modules/core/doc/basic_structures.html#mat). The comma operator is used for cv::Mat initialization:

// create a 3x3 double-precision identity matrix
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文