2014-08-27 69 views
12

當對具有顯式拷貝的對象進行排序時,我得到編譯器錯誤(來自g ++ 4.8.2和clang ++ 3.4,都在-std = C++ 11模式下)不明白。我創建了一個簡單的例子來說明這個問題顯式拷貝構造函數和std :: sort

class A { 
public: 
    explicit A(int i): m_i(i) {}; 
    explicit A(const A& other): m_i(other.m_i) {}; 
    int i() const {return m_i;}; 
private: 
    int m_i; 
}; 

bool is_less(const A& a, const A& b) { 
    return a.i() < b.i(); 
} 

int main(int, char*[]) { 
    std::vector<A> objects; 
    objects.push_back(A(3)); 
    objects.push_back(A(5)); 
    objects.push_back(A(-1)); 

    std::cout << is_less(objects[1], objects[2]); 
    std::sort(objects.begin(), objects.end(), is_less); 

    for (auto& a: objects) { 
    std::cout << a.i() << " "; 
    } 
    std::cout << std::endl; 
} 

這種失敗

error: 
    no matching constructor for initialization of '_ValueType' (aka 'A') 

在鐺++與

error: no matching function for call to ‘A::A(std::remove_reference<A&>::type) 
以g ++

。代碼編譯和工作正常,如果複製構造函數不明確(但我想強制只有對我的對象的引用可以用作參數和返回值)。該代碼還可以在刪除對std::sort的呼叫後編譯(因此is_less(objects[1], objects[2])不是問題)。因此,我的問題是什麼std :: sort在調用編譯該代碼失敗的比較函數以及如何修復它時會執行此操作。

經過大量研究,接近我的問題的唯一問題是In copy-initialization, is the call to the copy constructor explicit or implicit?,它鏈接到gcc中的錯誤。但是,clang顯示了相同的行爲,所以我很想知道發生了什麼。

+6

只有瘋狂的人使拷貝構造函數爲'explicit',這種類型不是CopyConstructible – 2014-08-27 14:38:13

回答

12

std::sort要求元素類型爲MoveConstructible

要求MoveConstructible指出表達式T u = rv;必須有效。但是,此表達式執行復制初始化並要求存在非顯式副本或移動構造函數。

在這種情況下,複製構造函數是顯式的,並聲明它意味着沒有隱式聲明的移動構造函數。因此,該表達式無效,並且類A不是MoveConstructible

+7

表達式無效的原因不僅僅是拷貝構造函數是顯式的,而且作爲僅在第一個拷貝構造函數中有副作用地方,移動構造函數被禁用。使用移動構造函數和移動賦值運算符,即使複製構造函數仍然是顯式的,它也可以工作。 – hvd 2014-08-27 14:42:24