I'm trying out the new range-v3 library (0.5.0, clang-7.1)
I'm traversing through a graph (bfs). Each node in the graph contains some vector data (std::vector<double>
). While traversing through the graph, I'm trying to create a concat_view
(which is concatenation of all the vectors).
I'm trying to store this concat_view
as a member variable of the graph traversal class. (default_bfs_visitor
from boost graph library, to be precise). So, upfront, I will not know how many vectors I'm going to encounter. I'm doing something like this.
struct bfs_visitor
{
private:
ranges::v3::any_view<double> mView;
public:
template<class Graph>
void finish_vertex (vertex_descriptor v, const Graph& g)
{
auto node = g[v];
std::vector<double>& data = dataForNode(node);
mView = ranges::v3::concat(mView, data);
}
};
After I'm done visiting the graph, I process the view to extract the required information.
As the type of mView
changes with each concat
operation, I'm unable to explicitly specify the type of mView
in the declaration.
This link says there's performance hit for any_view
. Is any_view
the only option?
You nail the issue on the head:
ranges::v3::concat
is different so you need type-erasure (any_view e.g.).In your situation I would not hesitate to replace view with a reified container:
Live On Coliru
struct bfs_visitor
{
private:
std::vector<std::reference_wrapper<double> > mView;
public:
template<class Graph>
void finish_vertex (vertex_descriptor v, const Graph& g)
{
auto& node = g[v];
ranges::v3::push_back(mView, dataForNode(node));
}
};
NOTE IMPORTANT
Note that I made
auto& node
a reference, instead of taking a copy. Concatenating views of temporary copies is a bad idea (UB).If you happen to know that
dataForNode(node)
does NOT return a reference to member data fromnode
, then this is not a real issue and you can disregard this comment.PHYSIC MODE ENGAGED:
If your issue was that
g
isGraph const&
and the view is not readonly, either
- make
mView
anany_view<double const>
- store a non-const pointer to your graph in the visitor and use that instead of the
g
argument
In fact, if you don't need them to be references at all (this is the key property of a view):
struct bfs_visitor
{
private:
std::vector<double> mCollectedData;
public:
template<class Graph>
void finish_vertex (vertex_descriptor v, const Graph& g) {
ranges::v3::push_back(mCollectedData, dataForNode(g[v]));
}
};
Note Another slightly weird thing is that your visitor templates the
Graph
argument type, but not thevertex_descriptor
. Again, it's hard to know whether it's actually wrong without seeing the rest of the code, but it's certainly a-typical.The vertex descriptor type is characteristic of the Graph type, so consider - writing
typename Graph::vertex_descriptor
ortypename boost::graph_traits<Graph>::vertex_descriptor
- making the operator() non-template
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With