【问题标题】:boost graph library, depth_first_search not calling finish_edge in msvc提升图形库,depth_first_search 不在 msvc 中调用 finish_edge
【发布时间】:2019-11-06 20:15:18
【问题描述】:

我正在使用 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,我们可以实际运行它来观察行为?这样可以节省很多时间

标签: c++ visual-studio boost visual-studio-2017 boost-graph


【解决方案1】:

您是否有我们可以实际运行以观察行为的 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

为了比较,

显然,它与 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.

【讨论】:

  • 嗯。也许是时候报告一个错误,它在您的编译器版本中仍然无法正常工作,因为我注意到您说您使用的是 Boost 1.70
【解决方案2】:

我在 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() {}

empty 方法永远不会被调用,但足以让 boost 检测到它。不用这样做就好了。

【讨论】:

    猜你喜欢
    • 2021-09-07
    • 1970-01-01
    • 2018-03-04
    • 2012-10-05
    • 1970-01-01
    • 2017-05-18
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多