作为数据成员的范围视图
range view as data member
我正在试用新的 range-v3 库(0.5.0,clang-7.1)
我正在遍历一个图 (bfs)。图中的每个节点都包含一些向量数据 (std::vector<double>
)。在遍历图表时,我试图创建一个 concat_view
(这是所有向量的串联)。
我正在尝试将此 concat_view
存储为图遍历 class 的成员变量。 (default_bfs_visitor
来自 boost 图形库,准确地说)。所以,预先,我不知道我会遇到多少向量。我正在做这样的事情。
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);
}
};
访问完图表后,我处理视图以提取所需的信息。
由于 mView
的类型随着每个 concat
操作而变化,我无法在声明中明确指定 mView
的类型。
This link 表示 any_view
的性能受到影响。 any_view
是唯一的选择吗?
你一针见血:
ranges::v3::concat
的 return 类型不同,因此您需要 type-erasure(例如 any_view)。
- 类型擦除惰性组合范围是个坏主意performance-wise
在你的情况下,我会毫不犹豫地用 reified 容器替换视图:
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 from node
, then this is not a real issue and you can disregard this comment.
PHYSIC MODE ENGAGED:
If your issue was that g
is Graph const&
and the view is not readonly,
either
- make
mView
an any_view<double const>
- store a non-const pointer to your graph in the visitor and use that instead of the
g
argument
事实上,如果你根本不需要它们作为引用(这是视图的关键属性):
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 the vertex_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
or typename boost::graph_traits<Graph>::vertex_descriptor
- making the operator() non-template
您可以存储any_view<double>
,正如您在原始问题中所写。
问题是您试图在运行时多次执行 | ranges::view::concat(...)
操作。每次连接范围时,都会创建不同的类型。
相反,您可以使用 ranges::view::join
到 "flatten" 双精度向量序列,进入双精度范围。看到这个问题,这很重要:
#include <iostream>
#include <set>
#include <vector>
#include <range/v3/all.hpp>
struct graph
{
using node_data = std::vector<double>;
private:
std::set<node_data> m_nodes;
ranges::v3::any_view<double> m_view; // Must be updated whenever a node is added/updated.
void update_view()
{
m_view = m_nodes | ranges::view::join;
}
public:
template<typename Container>
graph(const Container& c)
: m_nodes{std::begin(c), std::end(c)}
{
update_view();
}
std::size_t size() const { return m_nodes.size(); }
const ranges::v3::any_view<double>& data_view() const { return m_view; }
};
我试图为 join
迭代器的确切类型创建一个别名,而不是使用 any_view
,但我无法让它工作。 decltype
.
应该可以
这将按如下方式使用 (Wandbox link):
int main()
{
using node_data = graph::node_data;
auto data = {node_data{0.}, node_data{1.1, 2.2}, node_data{3.3, 4.4, 5.5}, node_data{6.6, 7.7, 8.8, 9.9}};
graph g{data};
std::cout << "Graph size (nodes): " << g.size() << std::endl;
std::cout << "Combined data: ";
auto r = g.data_view();
for (double val : r)
{
std::cout << val << " ";
}
}
输出:
Graph size (nodes): 4
Combined data: 0 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9
我正在试用新的 range-v3 库(0.5.0,clang-7.1)
我正在遍历一个图 (bfs)。图中的每个节点都包含一些向量数据 (std::vector<double>
)。在遍历图表时,我试图创建一个 concat_view
(这是所有向量的串联)。
我正在尝试将此 concat_view
存储为图遍历 class 的成员变量。 (default_bfs_visitor
来自 boost 图形库,准确地说)。所以,预先,我不知道我会遇到多少向量。我正在做这样的事情。
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);
}
};
访问完图表后,我处理视图以提取所需的信息。
由于 mView
的类型随着每个 concat
操作而变化,我无法在声明中明确指定 mView
的类型。
This link 表示 any_view
的性能受到影响。 any_view
是唯一的选择吗?
你一针见血:
ranges::v3::concat
的 return 类型不同,因此您需要 type-erasure(例如 any_view)。- 类型擦除惰性组合范围是个坏主意performance-wise
在你的情况下,我会毫不犹豫地用 reified 容器替换视图:
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
事实上,如果你根本不需要它们作为引用(这是视图的关键属性):
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
您可以存储any_view<double>
,正如您在原始问题中所写。
问题是您试图在运行时多次执行 | ranges::view::concat(...)
操作。每次连接范围时,都会创建不同的类型。
相反,您可以使用 ranges::view::join
到 "flatten" 双精度向量序列,进入双精度范围。看到这个问题,这很重要:
#include <iostream>
#include <set>
#include <vector>
#include <range/v3/all.hpp>
struct graph
{
using node_data = std::vector<double>;
private:
std::set<node_data> m_nodes;
ranges::v3::any_view<double> m_view; // Must be updated whenever a node is added/updated.
void update_view()
{
m_view = m_nodes | ranges::view::join;
}
public:
template<typename Container>
graph(const Container& c)
: m_nodes{std::begin(c), std::end(c)}
{
update_view();
}
std::size_t size() const { return m_nodes.size(); }
const ranges::v3::any_view<double>& data_view() const { return m_view; }
};
我试图为 join
迭代器的确切类型创建一个别名,而不是使用 any_view
,但我无法让它工作。 decltype
.
这将按如下方式使用 (Wandbox link):
int main()
{
using node_data = graph::node_data;
auto data = {node_data{0.}, node_data{1.1, 2.2}, node_data{3.3, 4.4, 5.5}, node_data{6.6, 7.7, 8.8, 9.9}};
graph g{data};
std::cout << "Graph size (nodes): " << g.size() << std::endl;
std::cout << "Combined data: ";
auto r = g.data_view();
for (double val : r)
{
std::cout << val << " ";
}
}
输出:
Graph size (nodes): 4
Combined data: 0 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9