2017-11-18 2 views
2

OK, dieser hat mich ratlos. Offensichtlich habe ich etwas verpasst, also hoffe ich, dass mir jemand sagen kann, was es ist.Shared_from_this() gibt std :: shared_ptr zurück <const X>, nicht std :: shared_ptr <X>

Ich entwickle eine C++ 17-Bibliothek. Ich habe eine benutzerdefinierte Baumdatenstruktur geschrieben, bestehend aus Node Objekten und einem benutzerdefinierten Iterator, Node::iterator, um den Baum zu durchlaufen. Der Iterator sieht wie folgt aus:

template <typename T> 
class NodeIterator { 
public: 
    using value_type = T; 
    using difference_type = std::ptrdiff_t; 
    using pointer = std::shared_ptr<T>; 
    using reference = T&; 
    using iterator_category = std::forward_iterator_tag; 

    NodeIterator() = default; 
    NodeIterator(pointer n); 

    // Etc. 
} 

Und später ...

template class NodeIterator<Node>; 
template class NodeIterator<const Node>; 

Als ich den Standard Iteratormethoden (begin(), end() und die const Äquivalente) zu einer Klasse Eltern hinzufügen Tree, kann ich Kontrolliere den Anfangswert für den Iterator. So kann ich sagen

Node::iterator Tree::begin() const { 
    return Node::iterator(_root); 
} 

wo _root ein std::shared_ptr<Node> ist. Das funktioniert großartig.

Allerdings nicht zufrieden genug zu verlassen, ich möchte diese Iterator-Methoden auf dem Knoten selbst. Auf diese Weise kann ich einen Teilbaum von einem beliebigen Knoten durchqueren, die Klasse Tree komplett eliminieren und einfach Node Objekte weitergeben.

Ich erkläre Node als

class Node : public std::enable_shared_from_this<Node> { 
public: 
    using iterator = NodeIterator<Node>; 
    using const_iterator = NodeIterator<const Node>; 

    iterator begin() const; 
    iterator end() const; 
    const_iterator cbegin() const; 
    const_iterator cend() const; 

    // Etc. 
} 

und die Iteratormethoden als

Node::iterator Node::begin() const { 
    return Node::iterator(this->shared_from_this()); 
} 

Node::iterator Node::end() const { 
    return Node::iterator(nullptr); 
} 

Node::const_iterator Node::cbegin() const { 
    return Node::const_iterator(this->shared_from_this()); 
} 

Node::const_iterator Node::cend() const { 
    return Node::const_iterator(nullptr); 
} 

Der Compiler definieren dann laut beschwert sich über die return Aussage:

src/node.cc:79:9: error: no matching conversion for functional-style cast from 
     'shared_ptr<const Node>' to 'Node::iterator' (aka 'NodeIterator<Node>') 
     return Node::iterator(this->shared_from_this()); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

und später ...

include/example.h:344:2: note: candidate constructor not viable: no known 
     conversion from 'shared_ptr<const Node>' to 'shared_ptr<Node>' for 
     1st argument 
     NodeIterator(pointer n); 
     ^

In einer anderen Methode, , setze ich automatisch den Elternknoten (std::shared_ptr<Node>) auf this->shared_from_this(), und es funktioniert gut.

Wenn ich Node::begin() und Node::end() kommentieren und nur cbegin() und cend() in meiner Schleife verwenden, funktioniert es auch in Ordnung.

Was gibt?

+0

Vermutlich ist eine Ihrer Mitgliedsfunktionen "const" und die andere nicht? –

Antwort

4

shared_from_this hat konstante und nicht-konstante Überladungen. Siehe cppreference. Innerhalb Ihres const begin, this ist Zeiger auf const und ruft die const Überladung auf, die eine shared_ptr zu const zurückgibt.

+0

Ich habe meine Frage aktualisiert, um weitere Einzelheiten zur Deklaration und Definition der Iteratormethoden hinzuzufügen. Können Sie etwas genauer erläutern, was Ihre vorgeschlagene Lösung wäre? –

+2

@MatthewRatzloff Haben 'begin() const' return ein' const_iterator' und 'begin()' (non-const) geben einen 'iterator' zurück, wie sie sollten. Die Fähigkeit, ein konstantes Objekt durch Iterieren zu verändern, wäre schlecht. –

+0

@ChrisDodd Vielen Dank! Ich dachte versehentlich 'cbegin()' und 'cend()' * waren * die konstanten Entsprechungen (Vektor, Liste, Karte ...).Habe nicht gemerkt, dass du 'begin()' und 'end()' einfach überladen solltest. Und mein Gehirn hat sich offensichtlich über das const am Ende der beiden ... –

Verwandte Themen