Доступ к типу свойства графового пакета, чтобы использовать его в SFINAE - PullRequest
1 голос
/ 28 апреля 2020

У меня есть код, который может обрабатывать различные типы (повышающих) графиков, и я хочу сделать что-то особенное для графиков, имеющих определенное c свойство комплекта.

Например, это:

struct VertexProp
{
    // some data
};

Мой код может использовать два типа графиков:

using graph1_t  = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::undirectedS,
    VertexProp
    > ;

или

using graph2_t = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::undirectedS
    > ;

Я намерен использовать SFINAE для включения функции, которая будет обрабатывать только эти c case:

template<Graph_t>
void foo
(
    const Graph_t& gr,
    std::enable_if<
        std::is_equal<SOME_TRAIT<Graph_t>::type,VertexProp>,T
        >::type* = nullptr
)
{
    // do something only for graphs having VertexProp
}

Я в порядке с чертами типа в общем случае (по крайней мере, я так думаю ...), но в данном случае это сторонний тип (boost::adjacency_list ).

И я не могу найти в предоставленные черты typedef, дающий мне этот тип. Я также проверил включенный код в руководстве, но не помогло.

Как я могу получить доступ к этому типу?

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Вы можете получить тип через черту property_map. Фактически тип-значения является признаком карты этого свойства:)

Итак, чтобы обнаружить расслоение вершин:

template <typename Graph, typename Bundle = typename boost::property_map<Graph, boost::vertex_bundle_t>::type>
    using VBundle = typename boost::property_traits<Bundle>::value_type;

Делаем это более читабельным с пробелами:

template <
    typename Graph,
    typename Bundle = 
        typename boost::property_map<Graph, boost::vertex_bundle_t>::type>
using VBundle =
    typename boost::property_traits<Bundle>::value_type;

Вы можете видеть, что мы запрашиваем property_traits карты свойств vertex_bundle_t.

Чтобы проверить, что это ожидаемый тип:

template <typename Graph>
    using HasVertexProp = std::is_same<VertexProp, VBundle<Graph> >;

Теперь вы можете использовать SFINAE. Или, как я предположил бы для случая, подобного этому: отправка тега;

namespace detail {
    template <typename Graph_t>
    void foo(const Graph_t& g, std::true_type) {
        print_graph(g, std::cout << "Graph with VertexProp bundle: ");
    }

    template <typename Graph_t>
    void foo(const Graph_t& g, std::false_type) {
        print_graph(g, std::cout << "Graph with other/missing properties: ");
    }
}

template <typename Graph_t>
void foo(const Graph_t& g) {
    detail::foo(g, HasVertexProp<Graph_t>{});
}

Давайте проверим это:

Live On Coliru

int main() {
    graph1_t g1(4);
    graph2_t g2(4);
    foo(g1);
    foo(g2);
}

Отпечатки

Graph with VertexProp bundle: 0 <--> 
1 <--> 
2 <--> 
3 <--> 
Graph with other/missing properties: 0 <--> 
1 <--> 
2 <--> 
3 <--> 
1 голос
/ 28 апреля 2020

Вы можете использовать параметр шаблона шаблона, чтобы назвать вложенные типы некоторых Graph_t, а затем указать, является ли любой из вложенных типов VertexProp, например:

template<template<typename ...> class Graph_t, typename ...Props>
auto foo(Graph_t<Props...>) 
  -> std::enable_if_t<
      std::disjunction<std::is_same<VertexProp, Props>...>{}>
{} 

и вы получить:

foo(graph1_t{});  // ok
foo(graph2_t{});  // error
...