2017-11-18 114 views
2

好吧,這一個讓我難住。顯然我錯過了一些東西,所以我希望有人能告訴我它是什麼。shared_from_this()返回std :: shared_ptr <const X>,而不是std :: shared_ptr <X>

我正在開發一個C++ 17庫。我寫了一個由Node對象和一個自定義迭代器Node::iterator組成的定製樹數據結構,用於遍歷樹。迭代器看起來是這樣的:

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. 
} 

後來......

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

當我添加的標準迭代方法(begin()end()和常量當量),從而Tree父類,我可以控制迭代器的初始值。所以我可以說

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

其中_rootstd::shared_ptr<Node>。這很好。

但是,不滿足於保持足夠的獨立,我希望這些迭代器方法在節點本身。這樣我可以遍歷任意節點的子樹,完全消除Tree類,並且只傳遞Node對象。

我宣佈Node作爲

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. 
} 

,並定義迭代方法爲

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); 
} 

然後,編譯器大聲抱怨的return聲明:

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()); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

和後...

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); 
     ^

在另一種方法,我自動將父節點(std::shared_ptr<Node>)設置爲this->shared_from_this(),它工作正常。

如果我在我的循環中註釋掉Node::begin()Node::end()並且只使用cbegin()cend(),它也可以正常工作。

什麼給?

+0

假設你的一個成員函數是'const',另一個不是? –

回答

4

shared_from_this有const和非const重載。見cppreference。在你的const begin中,this是指向const的指針並且調用const過載,它返回一個shared_ptr到const。

+0

我更新了我的問題,以添加更多關於我如何聲明和定義迭代器方法的詳細信息。你可以詳細瞭解一下你的建議解決方案嗎? –

+2

@MatthewRatzloff讓'begin()const'返回'const_iterator'和'begin()'(非const)返回一個'iterator',就像他們應該那樣。能夠通過迭代來修改一個const對象會很糟糕。 –

+0

@ChrisDodd謝謝!我錯誤地認爲'cbegin()'和'cend()'*是等價的常量(vector,list,map ...)。沒有意識到你應該重載'begin()'和'end()'。而且我的大腦明顯在這兩者的末尾扭曲了const ... –

相關問題