增强图形库,depth_first_search未在msvc

时间:2019-06-25 03:31:52

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

我在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

2 个答案:

答案 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

为进行比较,

因此,显然,与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 检测到它。不用这样做就好了。