Meh*_*dad 64 c++ function operator-overloading
我经常看到关于在C++中重载逗号运算符的问题(主要与重载本身无关,但是像序列点的概念一样),这让我想知道:
你什么时候应该重写逗号?它的实际用途有哪些例子?
我只是想不出任何我已经看到或需要的东西
foo, bar;
Run Code Online (Sandbox Code Playgroud)
在现实世界的代码中,所以我很好奇何时(如果有的话)实际使用它.
Pet*_*ter 134
我使用了逗号运算符来索引具有多个索引的映射.
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;
Run Code Online (Sandbox Code Playgroud)
ild*_*arn 61
让我们把重点改为:
你什么时候应该重写逗号?
答案:永远不会.
例外:如果你正在进行模板元编程,operator,
那么在运算符优先级列表的最底部有一个特殊的位置,这对于构建SFINAE防护等很方便.
我看到过重的两个实际用途operator,
都是在Boost中:
GMa*_*ckG 34
Boost.Assign使用它,让你做以下事情:
vector<int> v;
v += 1,2,3,4,5,6,7,8,9;
Run Code Online (Sandbox Code Playgroud)
而且我已经看到它用于古怪的语言黑客,我会看看我是否能找到一些.
啊哈,我确实记得其中一个古怪的用法:收集多个表达式.(警告,黑魔法.)
Ale*_* C. 23
逗号有一个有趣的属性,它可以采用类型的参数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)
Run Code Online (Sandbox Code Playgroud)
我让读者想出一个正在进行的练习.请记住,operator,
右边的同事.
Jos*_*ley 13
与@ 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;
Run Code Online (Sandbox Code Playgroud)
在SOCI - C++数据库访问库中,它用于实现接口的入站部分:
sql << "select name, salary from persons where id = " << id,
into(name), into(salary);
Run Code Online (Sandbox Code Playgroud)
从理论常见问题解答:
问:重载的逗号运算符只是混淆,我不喜欢它.
好吧,请考虑以下事项:
"将查询X发送到服务器Y并将结果放入变量Z."
在上面,"和"扮演逗号的角色.即使重载逗号运算符在C++中不是一种非常流行的实践,一些库也会这样做,实现简洁易学的语法.我们非常确定在SOCI中,逗号运算符过载效果很好.
我使用逗号运算符来打印日志输出。它实际上非常类似于ostream::operator<<
但我发现逗号运算符实际上更适合该任务。
所以我有:
template <typename T>
MyLogType::operator,(const T& data) { /* do the same thing as with ostream::operator<<*/ }
Run Code Online (Sandbox Code Playgroud)
它有这些不错的特性
逗号运算符的优先级最低。所以如果你想流式传输一个表达式,如果你忘记了括号,事情就不会搞砸了。相比:
myLog << "The mask result is: " << x&y; //operator precedence would mess this one up
myLog, "The result is: ", x&y;
Run Code Online (Sandbox Code Playgroud)
您甚至可以在内部混合比较运算符而不会出现问题,例如
myLog, "a==b: ", a==b;
Run Code Online (Sandbox Code Playgroud)逗号运算符在视觉上很小。将许多东西粘在一起时,不会影响阅读
myLog, "Coords=", g, ':', s, ':', p;
Run Code Online (Sandbox Code Playgroud)它与逗号运算符的含义一致,即“打印这个”然后“打印那个”。
沿着同样的路线,我发送了一个带逗号运算符重载的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)
Run Code Online (Sandbox Code Playgroud)
那么在我的代码中,我可以做到:
Log(2, "INFO: setting variable \", 1, "\"\n");
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么这是一个好的或坏的用例?
实际用途之一是在宏中有效地使用可变参数。顺便说一句,变量参数早期是 GCC 中的扩展,现在是 C++11 标准的一部分。
假设我们有一个class X
,它将类型的对象添加A
到其中。IE
class X {
public: X& operator+= (const A&);
};
Run Code Online (Sandbox Code Playgroud)
A
如果我们想向 中添加 1 个或多个对象怎么办X buffer;
?
例如,
#define ADD(buffer, ...) buffer += __VA_ARGS__
Run Code Online (Sandbox Code Playgroud)
上述宏,如果用作:
ADD(buffer, objA1, objA2, objA3);
Run Code Online (Sandbox Code Playgroud)
那么它将扩展为:
buffer += objA1, objeA2, objA3;
Run Code Online (Sandbox Code Playgroud)
因此,这将是使用逗号运算符的完美示例,因为变量参数也以相同的方式扩展。
因此,为了解决这个问题,我们重载comma
运算符并将其包装+=
如下
X& X::operator, (const A& a) { // declared inside `class X`
*this += a; // calls `operator+=`
}
Run Code Online (Sandbox Code Playgroud)