Я хочу узнать, как Концепции посетителей работает в библиотеке графов повышения, написав свой собственный вистор. Исходный код из 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;
};