2014-08-27 16 views
12

Podczas sortowania kontenera obiektów posiadających jawną kopię ctor otrzymuję błędy kompilatora (z g ++ 4.8.2 i clang ++ 3.4, oba w trybie -std = C++ 11), które 'nie rozumiem. Został utworzony prosty przykład, aby zilustrować problemJawny konstruktor kopiowania i 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; 
} 

zawiedzie to z

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

w brzękiem ++ iz

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

w g ++. Kod kompiluje się i działa poprawnie, jeśli konstruktor kopiowania nie jest jawny (ale chcę wymusić, aby tylko odwołania do moich obiektów mogły być używane jako parametry i zwracane wartości). Kod kompiluje się również po usunięciu wywołania do std::sort (więc is_less(objects[1], objects[2]) nie jest problemem). Stąd moje pytanie brzmi: co robi std :: sort, wywołując funkcję porównywania, która powoduje, że kompilowanie tego kodu kończy się niepowodzeniem i jak to naprawić.

Po wielu badaniach jedyne pytanie, które znalazło się blisko mojego problemu, to In copy-initialization, is the call to the copy constructor explicit or implicit?, które prowadzi do błędu w gcc. Jednak clang pokazuje to samo zachowanie, więc naprawdę chciałbym zrozumieć, co się dzieje.

+6

Tylko zwariowani ludzie konstruują "konstruktorów" jawnych, takie typy nie są CopyConstructible –

Odpowiedz

12

std::sort wymaga, aby typem elementu była MoveConstructible.

Wymagania dla MoveConstructible określają, że wyrażenie T u = rv; musi być prawidłowe. Jednak to wyrażenie wykonuje inicjowanie kopii i wymaga, aby istniał nie jawny egzemplarz lub konstruktor przenoszenia.

W tym przypadku konstruktor kopiowania jest jawny, a deklarowanie oznacza, że ​​nie istnieje niejawnie deklarowany konstruktor ruchu. Dlatego wyrażenie jest nieprawidłowe, a klasa A nie jest MoveConstructible.

+7

To, co sprawia, że ​​wyrażenie jest nieważne, nie jest tylko tym, że konstruktor kopiowania jest jawny, ale także jako efekt uboczny jedynie posiadania konstruktora kopii w pierwszym miejsce, konstruktor ruchu jest wyłączony. Z konstruktorem ruchu i operatorem przypisania ruchu działa, nawet jeśli konstruktor kopiowania jest nadal jawny. – hvd

Powiązane problemy