我在vs-2017上使用Boost 1.70.0。使用depth_first_search
时,我发现使用msvc编译器进行编译时,不会调用访问者中的finish_edge
函数。使用gcc(8.3)可以正确调用finish_edge
函数
示例代码:
struct DfsVisitor : public boost::default_dfs_visitor
{
template <class Graph>
void
finish_edge(typename Graph::edge_descriptor ed, const Graph& g)
{
std::cout << "Finish edge " << boost::source(ed, g) << "->" << boost::target(ed, g) << std::endl;
}
};
DfsVisitor dfs;
boost::depth_first_search(g, boost::visitor(dfs)); // g is graph, adjacency_list
答案 0 :(得分:0)
您是否有SSCCE,我们可以实际运行以观察其行为?这样可以节省很多时间
我就是这么做的:就是这么做的:repro Boost 1.60 on msvc
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <iostream>
struct DfsVisitor : public boost::default_dfs_visitor {
template <class Graph> void finish_edge(typename Graph::edge_descriptor ed, const Graph &g) {
std::cout << "Finish edge " << boost::source(ed, g) << "->" << boost::target(ed, g) << std::endl;
}
};
int main() {
boost::adjacency_list<> g(4);
add_edge(0,1,g);
add_edge(1,2,g);
add_edge(2,3,g);
DfsVisitor dfs;
boost::depth_first_search(g, boost::visitor(dfs));
std::cout << "Done\n";
}
只需打印:
Done
为进行比较,
在GCC 9.1上提升1.70可以打印正确的输出:(https://godbolt.org/z/PMbEFL)
Finish edge 2->3
Finish edge 1->2
Finish edge 0->1
因此,显然,与Boost版本的关系比与编译器的关系更大。 Godbolt没有比Boost 1.64更远(仍然可以:https://godbolt.org/z/Ld8-8d),但是wandbox可以做到:
检查release notes for Boost 1.62.0似乎没有提到什么,但是使用github历史记录确实可以发现:
$ git clone https://github.com/boostorg/graph
$ cd graph
$ git log --oneline --graph --left-right --cherry-pick boost-1.61.0...boost-1.62.0 | grep -i finish
> a14f8df8 Fixed bug 10231 partly: If finish_edge was called, then now correctly. (#16)
> d6b7a717 Add finish_edge test case from Alex Lauser.
> 6a2d45ae Condition TTI finish_edge on supported compilers.
> 0e1414f4 Fix type traits so finish_edge is called when defined.
答案 1 :(得分:0)
我在 boost-1.70 和 VS-2013 (x64, 18.00) 上遇到了同样的问题。查看 implementation in boost,其他编译器的实现与 GCC、Clang 或 Intel 编译器不同:
template <typename E, typename G, typename Vis>
void call_finish_edge(Vis& vis, E e, const G& g) { // Only call if method exists
#if ((defined(__GNUC__) && (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))) || \
defined(__clang__) || \
(defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1200)))
do_call_finish_edge<
has_member_function_finish_edge<Vis, void,
boost::mpl::vector<E, const G&> >::value>::call_finish_edge(vis, e, g);
#else
do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
#endif
}
对于其他编译器,调用方法has_member_function_finish_edge
(由宏BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
产生)时,参数不作为模板参数给出
所以我们可以通过添加另一个不带参数的空方法来让 boost 检测它:
template <class Edge, class Graph>
void finish_edge(Edge e, Graph& g) {
std::cout << "finish_edge e=" << e << std::endl;
}
void finish_edge() {}
空方法永远不会被调用,但足以让 boost 检测到它。不用这样做就好了。