OK, this one has me stumped. Clearly I've missed something, so I hope someone can tell me what it is.
I'm developing a C++17 library. I've written a custom tree data structure composed of Node
objects and a custom iterator, Node::iterator
, for traversing the tree. The iterator looks like this:
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.
}
And later...
template class NodeIterator<Node>;
template class NodeIterator<const Node>;
When I add the standard iterator methods ( begin()
, end()
, and the const equivalents) to a parent class Tree
, I can control the initial value for the iterator. So I can say
Node::iterator Tree::begin() const {
return Node::iterator(_root);
}
where _root
is a std::shared_ptr<Node>
. This works great.
However, not content to leave well enough alone, I want these iterator methods on the node itself. That way I can traverse a subtree from any node, eliminate the Tree
class altogether, and just pass around Node
objects.
I declare Node
as
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.
}
and define the iterator methods as
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);
}
The compiler then loudly complains about the return
statement:
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());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
and later...
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 another method, Node::appendChild()
, I automatically set the parent node ( std::shared_ptr<Node>
) to this->shared_from_this()
, and it works fine.
If I comment out Node::begin()
and Node::end()
and only use cbegin()
and cend()
in my loop, it also works fine.
What gives?
shared_from_this
has const and non-const overloads. See cppreference . Within your const begin
, this
is pointer to const and calls the const overload which returns a shared_ptr
to const.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.