為什麼C++的逗號運算符是可以重載的?
是什麼因素使得運算符重載在C++中引入時把逗號運算符也作為可重載的運算符?
@邱昊宇 的回答已經講得很清楚了, 我舉個重載逗號運算符的應用
Folly:Expected 是一個類似於 Optional 的類型,不過它存儲的是值或者錯誤.它可以用一串then來鏈式調用若干各函數,順便還能檢查參數類型是否匹配.
{
Expected&
Expected&
[](std::unique_ptr&
[](int i) { return i == 42 ? "yes" : "no"; });
EXPECT_TRUE(bool(ex));
EXPECT_EQ("yes", *ex);
}
Expected&
ex.then([](int) {})
.then([](Unit) { std::cout &<&< "hello "; })
.then([](Unit) { std::cout &<&< "world
"; });
void類型是沒有值, 於是我們用Unit來替代它(其實就是空的struct)
每一個then其實是返回一個Folly::Expected, 裡面存儲著對應類型的值或者錯誤. then的調用會轉發給內部的then_ template &<
class This,
class Fn,
class... Fns,
class E = ExpectedErrorType&
class T = ExpectedHelper&>
static auto then_(This ex, Fn fn, Fns... fns) -&> decltype(T::then_(
T::template return_&
(std::declval&
std::declval&
if (LIKELY(ex.which_ == expected_detail::Which::eValue))
return T::then_(
T::template return_&
// Uses the comma operator defined above IFF the lambda
// returns non-void.
(static_cast&
static_cast&
return makeUnexpected(static_cast&
}
如果then接受的函數返回類型是void,那麼我們需要把它轉換成Unit類型. 這種情況下
(static_cast&
中的逗號運算符是沒重載的版本,值是第二個操作數.
如果then接受函數的返回類型不是void,會使用重載的逗號運算符,返回第一個操作數的值.namespace expected_detail_ExpectedHelper {
// Tricky hack so that Expected::then can handle lambdas that return void
template &
inline T operator,(T t, Unit) noexcept {
return static_cast&
}
因為有時候真的有用啊。opencv中有下面的矩陣初始化方法:
Mat C = (Mat_&
我頭一次看到的時候百思不得其解,後來特意翻了翻源碼才發現是重載了逗號運算符。
補充下 @邱昊宇 提到的微小的工作。
Qt中的信號槽,在同步執行時,槽函數的返回值直接由信號函數返回。信號函數可以是void返回值,也可以是和槽函數相同的返回值。
在源碼實現里,有返回值的信號函數和返回void的信號函數是同一個流程。而當槽函數的返回值傳遞過去時,就是用重載逗號運算符實現的。// 執行槽函數的代碼
template &
template &
struct FunctorCall&
static void call(Function f, void **arg) {
f((*reinterpret_cast&
}
};
template &
struct FunctorCall&
static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) {
(o-&>*f)((*reinterpret_cast&
}
};
template &
struct FunctorCall&
static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg) {
(o-&>*f)((*reinterpret_cast&
}
};
// 逗號運算符封裝返回值 這裡,通過重載逗號運算符,加上模板偏特化,實現了這個返回值自動封裝操作
/*
trick to set the return value of a slot that works even if the signal or the slot returns void
to be used like function(), ApplyReturnValue&
if function() returns a value, the operator,(T, ApplyReturnValue&
returns void, the builtin one is used without an error.
*/
template &
struct ApplyReturnValue {
void *data;
explicit ApplyReturnValue(void *data_) : data(data_) {}
};
template&
void operator,(const T value, const ApplyReturnValue& container) {
if (container.data)
*reinterpret_cast&(container.data) = value;
}
template&
void operator,(T value, const ApplyReturnValue& container) {
if (container.data)
*reinterpret_cast&(container.data) = value;
}
template&
void operator,(T, const ApplyReturnValue&
允許重載逗號運算符的原因,The Design and Evolution of C++ 里是這麼說的:
11.5.5 Overloading the Comma Operator
At the urging of Margaret Ellis, I allowed overloading of the comma operator. Basically, I couldn"t find any reason not to at the time. Actually, there is a reason: a, b is already defined for any a and b, so allowing overloading enables the programmer to change the meaning of a built-in operator. Fortunately, that is only possible if either a or b is a class object. There appear to be few practical uses of operator,(). Accepting it was primarily a generalization.
大致就是
- 有人催
- 反正重載一下也不會懷孕
- 而且真的有人利用重載逗號運算符做了點(微小的)工作
p.s. 這一章開頭也有提到,在重載運算符這方面「只要重載有意義、不與運算符本身的語義相悖,目標是允許重載所有操作符」。
真的假的?我試試
記得DE裡面有說,因為其他雙目運算符都是能重載的,為了完整性就讓逗號運算符也可以重載了
啥,逗號可以重載?
只要是語法分析階段,能確定的,都不會影響效率,頂多編譯慢一些。只要,別學py,玩動態多態性就好。
推薦閱讀:
※模擬示波器通常是什麼樣的架構什麼系統,如何編程(有人在日立V-422上編寫了一款FPS遊戲)?
※有什麼好方法能把高數和編程聯繫起來么?
※Android 應用中半透明狀態欄的原理是什麼?(有分歧故來提問)
※碼農需要的基本款電腦是怎樣的配置?
※C語言標準中為什麼不規定int類型的具體長度?