[英]boost graph library, depth_first_search not calling finish_edge in msvc
我正在使用 Boost 1.70.0,與 vs-2017。 使用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
您是否有一個 SSCCE,我們可以實際運行它來觀察行為? 這樣會節省很多時間
我就是這樣做的:就是這樣做的:在 msvc 上重現Boost 1.60
#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 上的 Boost 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 確實:
檢查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.
我在 boost-1.70 和 VS-2013 (x64, 18.00) 上遇到了同樣的問題。 查看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 檢測到它。 不必這樣做就好了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.