使用 std::unique_ptr 提升图形捆绑属性
Boost graph bundled properties with std::unique_ptr
将 std::unique_ptr
显示为带有 boost-graph 的捆绑 属性 的成员。
提供的例子可以试用
Live On Coliru.
由于我只对设计方面感兴趣,而不是该答案的算法部分,因此我提供了一个简化示例 Live On Coliru.
#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
struct custom_node{
custom_node(std::string name, int capacity) : name(name), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
};
void usage(){}
using namespace boost;
struct VertexProperties {
int id;
std::unique_ptr<custom_node> node;
};
typedef adjacency_list<vecS, vecS, directedS, VertexProperties> DirectedGraph;
typedef graph_traits<DirectedGraph>::vertex_descriptor custom_vertex;
typedef graph_traits<DirectedGraph>::edge_descriptor custom_edge;
int main() {
DirectedGraph g;
boost::add_vertex(g);
g[0].node = std::make_unique<custom_node>("inner", 2);
////boost::add_vertex(VertexProperties{0, std::make_unique<custom_node>("inner", 2)}, g); // compilation error
std::cout << boost::num_vertices(g);
std::cout << g[0].id << "\n";
std::cout << g[0].node->name << "\n";
std::cout << g[0].node->capacity << "\n";
}
可以通过boost::add_vertex(g)
添加顶点,然后实例化std::unique_ptr
。
如果我试图通过在 add_vertex
中通过列表初始化创建具有所有属性的顶点来实现相同的目的,则会出现关于 implicitly-deleted copy constructor of 'VertexProperties'
的编译错误。
VertexProperties
当然删除了它的复制构造函数,因为 std::unique_ptr
删除了它的复制构造函数。
为什么一开始就需要复制构造函数来初始化列表?是不是有什么不明白的地方,或者这是boost-graph的缺点?
Why is the copy constructor is necessary for list initialization in the first place? Is there something I do not understand about it, or is this a shortcoming of boost-graph?
这不是一回事,也不是正在发生的事情。
Aside: in copy-initialization the assignment can be elided by the compiler, but operator= still needs to be accessible for it to be valid code.
但在这种情况下,只是库代码没有移动感知。您必须意识到“捆绑”属性是单独存储的。无论如何,bundle(任何 属性)都必须是默认可构造的(因此 add_vertex(g)
有效),因此通过始终分配给默认构造的 属性.[=30= 来简化实现]
因为它不是移动感知的,赋值不会转发右值,所以不会编译。
选项
链接的答案已经显示:
if(g[v].node_logic) {
g[v].node.reset(new custom_node(g[v].vertex_name, 0, standby, normal));
}
更多选项:
VertexProperties props {0,
std::make_unique<custom_node>("inner", 2)};
auto vd = boost::add_vertex(g);
g[vd] = std::move(props);
收拾你的狗屎!您可以创建您喜欢的任何界面:
auto add_vertex = [&g](VertexProperties&& props) {
auto vd = boost::add_vertex(g);
g[vd] = std::move(props);
return vd;
};
add_vertex({0, std::make_unique<custom_node>("inner", 2)});
你甚至可以详细说明:
auto add_vertex = [&g](int id, std::string name, int capacity = -1) {
auto vd = boost::add_vertex(g);
g[vd] = { id, std::make_unique<custom_node>(name, capacity) };
return vd;
};
add_vertex(0, "inner", 2);
add_vertex(1, "outer", 3);
add_vertex(2, "other");
以上所有选项Live On Coliru
如果你问我,无论如何后一个界面要好得多。
如果您愿意,可以使用 ADL 使其可供其他人使用:
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
namespace MyLib { // for ADL demo
struct custom_node {
custom_node(std::string name, int capacity)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::unique_ptr<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node)
os << ", " << *vp.node;
return os;
}
};
template <typename G>
auto add_vertex(G& g, int id, const std::string& name, int capacity = -1) {
auto vd = boost::add_vertex(g);
g[vd] = { id, std::make_unique<custom_node>(name, capacity) };
return vd;
}
}
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, MyLib::VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex(g, 10, "inner", 2);
add_vertex(g, 11, "outer", 3);
add_vertex(g, 12, "other");
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
版画
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}
有人提到设计?
如果您想要的只是具有 optional/lazy 结构的独特所有权,为什么不呢:
struct VertexProperties {
int id{};
std::optional<custom_node> node;
};
甚至只是
struct VertexProperties {
int id{};
custom_node node;
};
所有权语义将相同,但没有成本:
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
这只是使用来自 BGL 的标准 boost::add_vertex
重载。没有 optional<>
它可以变得更简单:
add_vertex({10, {"inner", 2}}, g);
add_vertex({11, {"outer", 3}}, g);
add_vertex({12, {"other"}}, g);
还有Live On Coliru (without std::optional: Live)
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include <optional>
struct custom_node {
custom_node(std::string name, int capacity = -1)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::optional<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node) os << ", " << *vp.node;
return os;
}
};
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
版画
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}
std::unique_ptr
显示为带有 boost-graph 的捆绑 属性 的成员。
提供的例子可以试用 Live On Coliru.
由于我只对设计方面感兴趣,而不是该答案的算法部分,因此我提供了一个简化示例 Live On Coliru.
#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
struct custom_node{
custom_node(std::string name, int capacity) : name(name), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
};
void usage(){}
using namespace boost;
struct VertexProperties {
int id;
std::unique_ptr<custom_node> node;
};
typedef adjacency_list<vecS, vecS, directedS, VertexProperties> DirectedGraph;
typedef graph_traits<DirectedGraph>::vertex_descriptor custom_vertex;
typedef graph_traits<DirectedGraph>::edge_descriptor custom_edge;
int main() {
DirectedGraph g;
boost::add_vertex(g);
g[0].node = std::make_unique<custom_node>("inner", 2);
////boost::add_vertex(VertexProperties{0, std::make_unique<custom_node>("inner", 2)}, g); // compilation error
std::cout << boost::num_vertices(g);
std::cout << g[0].id << "\n";
std::cout << g[0].node->name << "\n";
std::cout << g[0].node->capacity << "\n";
}
可以通过boost::add_vertex(g)
添加顶点,然后实例化std::unique_ptr
。
如果我试图通过在 add_vertex
中通过列表初始化创建具有所有属性的顶点来实现相同的目的,则会出现关于 implicitly-deleted copy constructor of 'VertexProperties'
的编译错误。
VertexProperties
当然删除了它的复制构造函数,因为 std::unique_ptr
删除了它的复制构造函数。
为什么一开始就需要复制构造函数来初始化列表?是不是有什么不明白的地方,或者这是boost-graph的缺点?
Why is the copy constructor is necessary for list initialization in the first place? Is there something I do not understand about it, or is this a shortcoming of boost-graph?
这不是一回事,也不是正在发生的事情。
Aside: in copy-initialization the assignment can be elided by the compiler, but operator= still needs to be accessible for it to be valid code.
但在这种情况下,只是库代码没有移动感知。您必须意识到“捆绑”属性是单独存储的。无论如何,bundle(任何 属性)都必须是默认可构造的(因此 add_vertex(g)
有效),因此通过始终分配给默认构造的 属性.[=30= 来简化实现]
因为它不是移动感知的,赋值不会转发右值,所以不会编译。
选项
链接的答案已经显示:
if(g[v].node_logic) { g[v].node.reset(new custom_node(g[v].vertex_name, 0, standby, normal)); }
更多选项:
VertexProperties props {0, std::make_unique<custom_node>("inner", 2)}; auto vd = boost::add_vertex(g); g[vd] = std::move(props);
收拾你的狗屎!您可以创建您喜欢的任何界面:
auto add_vertex = [&g](VertexProperties&& props) { auto vd = boost::add_vertex(g); g[vd] = std::move(props); return vd; }; add_vertex({0, std::make_unique<custom_node>("inner", 2)});
你甚至可以详细说明:
auto add_vertex = [&g](int id, std::string name, int capacity = -1) { auto vd = boost::add_vertex(g); g[vd] = { id, std::make_unique<custom_node>(name, capacity) }; return vd; }; add_vertex(0, "inner", 2); add_vertex(1, "outer", 3); add_vertex(2, "other");
以上所有选项Live On Coliru
如果你问我,无论如何后一个界面要好得多。
如果您愿意,可以使用 ADL 使其可供其他人使用:
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
namespace MyLib { // for ADL demo
struct custom_node {
custom_node(std::string name, int capacity)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::unique_ptr<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node)
os << ", " << *vp.node;
return os;
}
};
template <typename G>
auto add_vertex(G& g, int id, const std::string& name, int capacity = -1) {
auto vd = boost::add_vertex(g);
g[vd] = { id, std::make_unique<custom_node>(name, capacity) };
return vd;
}
}
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, MyLib::VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex(g, 10, "inner", 2);
add_vertex(g, 11, "outer", 3);
add_vertex(g, 12, "other");
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
版画
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}
有人提到设计?
如果您想要的只是具有 optional/lazy 结构的独特所有权,为什么不呢:
struct VertexProperties {
int id{};
std::optional<custom_node> node;
};
甚至只是
struct VertexProperties {
int id{};
custom_node node;
};
所有权语义将相同,但没有成本:
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
这只是使用来自 BGL 的标准 boost::add_vertex
重载。没有 optional<>
它可以变得更简单:
add_vertex({10, {"inner", 2}}, g);
add_vertex({11, {"outer", 3}}, g);
add_vertex({12, {"other"}}, g);
还有Live On Coliru (without std::optional: Live)
#include <boost/graph/adjacency_list.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include <optional>
struct custom_node {
custom_node(std::string name, int capacity = -1)
: name(std::move(name)), capacity(capacity) {}
std::string name = "uninitialized";
int capacity = -1;
friend std::ostream& operator<<(std::ostream& os, custom_node const& cn) {
return os << "{" << std::quoted(cn.name) << ", " << cn.capacity << "}";
}
};
struct VertexProperties {
int id{};
std::optional<custom_node> node;
friend std::ostream& operator<<(std::ostream& os, VertexProperties const& vp) {
os << vp.id;
if (vp.node) os << ", " << *vp.node;
return os;
}
};
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProperties>;
using custom_vertex = Graph::vertex_descriptor;
using custom_edge = Graph::edge_descriptor;
int main() {
Graph g;
add_vertex({10, custom_node{"inner", 2}}, g);
add_vertex({11, custom_node{"outer", 3}}, g);
add_vertex({12, custom_node{"other"}}, g);
for (auto vd : boost::make_iterator_range(vertices(g))) {
std::cout << g[vd] << "\n";
}
}
版画
10, {"inner", 2}
11, {"outer", 3}
12, {"other", -1}