Почему шаблон CRTP используется в Visitor в библиотеке графов надстроек? - PullRequest
0 голосов
/ 08 мая 2018

Я хочу узнать, как Концепции посетителей работает в библиотеке графов повышения, написав свой собственный вистор. Исходный код из base visitor и time_stamper EventVisitor есть,

  // needed for MSVC workaround
  template <class Visitor>
  struct base_visitor {
    typedef on_no_event event_filter;
    template <class T, class Graph>
    void operator()(T, Graph&) { }
};

  template <class TimeMap, class TimeT, class Tag>
  struct time_stamper
    : public base_visitor<time_stamper<TimeMap, TimeT, Tag> >
  {
    typedef Tag event_filter;
    time_stamper(TimeMap pa, TimeT& t) : m_time_pa(pa), m_time(t) { }
    template <class Vertex, class Graph>
    void operator()(Vertex u, const Graph&) {
      put(m_time_pa, u, ++m_time);
    }
    TimeMap m_time_pa;
    TimeT& m_time;
};

time_stamper - это класс, производный от базового класса base_visitor. Тип аргумента шаблона базового класса - это сам производный класс. Я считаю, что этот шаблон называется любопытно повторяющимся шаблоном (CRTP).

Мой вопрос: почему здесь используется CRTP? Страница wikipedia показывает, что CRTP часто используется для достижения статического полиморфизма, но в этом случае он не выглядит так.

Я сам реализую простого посетителя.

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/random.hpp>
#include <iostream>
#include <random>

using namespace boost;
using Graph = adjacency_list<vecS, vecS, directedS>;

struct tree_edge_event_visitor
  : public base_visitor<tree_edge_event_visitor> // works without this line
{
    using event_filter = on_tree_edge;
    template <class Edge, class Graph>
    void operator()(Edge u, Graph const& g)
    {   
        std::cout << source(u, g) << "->" << target(u, g) << '\n';
    }   
};

int main()
{
    Graph g;
    std::random_device rd; 
    std::mt19937 engine(rd());
    generate_random_graph(g, 10, 16, engine);
    write_graphviz(std::cout, g); 

    std::vector<default_color_type> color(num_vertices(g));
    std::cout << "Writing out tree edges: ";
    depth_first_visit(g, 0, dfs_visitor(tree_edge_event_visitor()),
        make_iterator_property_map(color.begin(), get(vertex_index, g)));

    return 0;
}

Он работает и продолжает работать без , полученного из base_visitor (см. Комментарий в коде). Так почему же здесь используется CRTP? Комментарий need for MSVC workround указывает на то, что этот шаблон предназначен только для MSVC.

Обновление : изменение сделано здесь в 2000 году. Более старая версия time_stamper не использует CRTP. Я думаю, что обоснование использования CRTP является специфическим для очень старой версии MSVC. К сожалению, я не могу проверить это в современном MSVC, так как у меня нет Windows-машины.

  template <class TimePA, class TimeT, class Tag>
  struct time_stamper {
    typedef Tag event_filter;
    time_stamper(TimePA pa, TimeT& t) : m_time_pa(pa), m_time(t) { }
    template <class Vertex, class Graph>
    void operator()(Vertex u, const Graph& g) {
      put(m_time_pa, u, ++m_time);
    }
    TimePA m_time_pa;
    TimeT& m_time;
};
...