2013-06-12 26 views
4

以下語法是工作在OpenCV的`運營商<<`在C++逗號分隔值

Mat R = (Mat_<double>(4, 4) << 
     1,   0,   0, 0, 
     0, cos(alpha), -sin(alpha), 0, 
     0, sin(alpha), cos(alpha), 0, 
     0,   0,   0, 1); 

如何可以嗎?什麼操作符被重載?這種表達意義是什麼?在當今C++中,逗號運算符是否可以超載?

+4

沒錯,逗號操作符可以被重載。唯一不能重載的是範圍解析op('::'),點('.')和三元操作符('?:')。 –

+0

您需要查看代碼。也許它使用[表達式模板](http://stackoverflow.com/questions/2598579/c-expression-templates) – ruben2020

回答

4

雖然通常不推薦使用逗號運算符(在很多情況下重載的逗號會令人困惑),但逗號運算符可能會被重載。

以上表達式爲4 * 4矩陣定義了16個值。如果你想知道這是如何可能的,我會展示一個更簡單的例子。假設我們希望能夠寫類似

MyVector<double> R = (MyVector<double>() << 1 , 2 , 3); 

那麼我們可以定義MyVector使<<,運營商追加新值向量:

template<typename T> 
class MyVector: public std::vector<T> { 
public: 
    MyVector<T>& operator << (T value) { push_back(value); return *this; } 
    MyVector<T>& operator , (T value) { push_back(value); return *this; } 
    ... 
}; 
3

下面是實際的代碼taken from here,如你可以看到operator,正在使用:

template<typename _Tp> template<typename T2> inline MatCommaInitializer_<_Tp>& 
MatCommaInitializer_<_Tp>::operator , (T2 v) 
{ 
    CV_DbgAssert(this->it < ((const Mat_<_Tp>*)this->it.m)->end()); 
    *this->it = _Tp(v); ++this->it; 
    return *this; 
} 

這需要下一個值,只是將其放在矩陣,遞增迭代器,然後返回對象MatCommaInitializer的引用(所以這些運算符可以鏈接在一起)。

2

以下是OpenCV的源代碼。我們可以知道類MatCommaInitializer_重載了,運算符,並在全局靜態字段中重載了運算符<<

` 
core.hpp 
... 
template<typename _Tp> class MatCommaInitializer_ 
{ 
public: 
    //! the constructor, created by "matrix << firstValue" operator, where matrix is cv::Mat 
    MatCommaInitializer_(Mat_<_Tp>* _m); 
    //! the operator that takes the next value and put it to the matrix 
    template<typename T2> MatCommaInitializer_<_Tp>& operator , (T2 v); 
    //! another form of conversion operator 
    Mat_<_Tp> operator *() const; 
    operator Mat_<_Tp>() const; 
protected: 
    MatIterator_<_Tp> it; 
}; 
... 
` 

` 
mat.hpp 
... 
template<typename _Tp, typename T2> static inline MatCommaInitializer_<_Tp> 
operator << (const Mat_<_Tp>& m, T2 val) 
{ 
    MatCommaInitializer_<_Tp> commaInitializer((Mat_<_Tp>*)&m); 
    return (commaInitializer, val); 
} 
... 
` 

所以你的代碼的工作過程如下:

  1. Mat_(4,4)創建一個包含4種4 double類型的列元素的實例。

  2. 然後調用<<重載操作符並返回MatCommaInitializer_實例。

  3. 然後它調用,重載操作符並返回MatCommaInitializer_實例,等等。

  4. 最後調用構造Mat(const MatCommaInitializer_<_Tp>& commaInitializer)