何时超载逗号运算符?

我常常在C ++上看到关于重载逗号操作符的问题(主要与重载本身无关,但是像序列点的概念),这让我怀疑:

应该什么时候超过逗号? 什么是它的实际用途的一些例子?

我只是想不出任何我曾经见过或需要的东西

foo, bar; 

在真实世界的代码中,所以我很好奇什么时候(如果有的话)这是实际使用的。

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

应该什么时候超过逗号?

答案:从来没有。

例外:如果你正在进行模板元编程, operator,在运算符优先级列表的最底部有一个特殊的位置,这对于构buildSFINAE-guard等来说可以派上用场。

我见过的重载operator,只有两个实际用途operator,都是在Boost中 :

  • Boost.Assign
  • Boost.Phoenix – 它的基本function是允许Phoenix lambda支持多种语句

我已经使用逗号运算符来索引具有多个索引的地图。

 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; 

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

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

我已经看到它用于古怪的语言黑客,我会看看如果我能find一些。


啊哈,我记得那些古怪的用途之一: 收集多个expression式 。 (警告,黑魔法。)

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

当你想确定一个expression式是否有voidtypes的时候,这是很方便的:

 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) 

我让读者把它看作是一个正在发生的事情。 请记住, operator,正确的联系。

类似于@ GMan的 Boost.Assign示例, Blitz ++重载了逗号运算符,以便为使用multidimensional array提供方便的语法 。 例如:

 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; 

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

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

从理由FAQ :

Q:重载的逗号操作符只是混淆,我不喜欢。

那么,请考虑以下几点:

“将查询X发送到服务器Y,并将结果放到variablesZ中。

以上,“和”起着逗号的作用。 即使重载逗号运算符在C ++中不是一个非常stream行的做法,有些库会这样做,实现简洁易学的语法。 我们非常确定,在SOCI中,逗号运算符超载的效果很好。

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

提升精神可能会重载逗号运算符(它几乎重载其他所有内容)

沿着同样的思路,我发送了一个包含逗号运算符重载的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"); 

有人可以解释为什么这是一个好或坏的使用情况?

其中一个实际用法是在macros中有效地使用它的可变参数。 顺便说一下,可变参数是GCC中的一个扩展,现在是C ++ 11标准的一部分。

假设我们有一个class X ,它添加了typesA对象。 即

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

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

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

以上macros,如果用作:

 ADD(buffer, objA1, objA2, objA3); 

那么它会扩展到:

 buffer += objA1, objeA2, objA3; 

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

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

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

这里是OpenCV文档( http://docs.opencv.org/modules/core/doc/basic_structures.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);