Можно ли передать шаблонные параметры шаблона поля в качестве первого параметра шаблона? - PullRequest
0 голосов
/ 04 июля 2019

У меня есть следующий метод в template <class Base> class foo {}:

template <
    typename V,
    template <class, class> class Map,
    Map<std::string, V> Base::*Field,
    std::size_t Len
>
constexpr const foo<Base> s(char const (&section_name)[Len]) const {
    #pragma unused(section_name)
    return *this;
}

Моя цель - иметь возможность вызывать его просто с помощью:

struct my_struct {
    std::map<std::string, int> section;
    constexpr auto bar = foo<my_struct>()
        .s<&my_struct::section>("hi");
};

Возможно ли это, возможно, черезспециализация?Я не могу обернуть голову, как заставить это даже компилироваться, поскольку в настоящее время я не могу передать указатель на член, так как шаблонный тип Map стоит первым в объявлении, что дает мне следующее для clang:

примечание: шаблон кандидата игнорируется: недопустимый явно заданный аргумент для параметра шаблона 'Map'

И я не могу заставить магические заклинания специализации работать,либо:

template <auto FieldType, std::size_t Len>
constexpr const foo<Base> s(char const (&section_name)[Len]) const;

template <
    template <class, class> class Map,
    typename SecType,
    Map<std::string, SecType> Base::*Field,
    std::size_t Len
>
constexpr const foo<Base> s<Field, Len>(char const (&section_name)[Len]) const {

}

, что дает

ошибка: частичная специализация шаблона функции не разрешена

Возможно ли то, что я после?Стоит упомянуть c ++ 14 и далее - все в порядке.

1 Ответ

0 голосов
/ 04 июля 2019

Для решения до C ++ 17 вы можете поместить указатель члена в std::integral_constant.Чтобы убедиться, что типом ключа вашей карты является std::string, используйте тип удержания, чтобы получить тип элемента от указателя и сравнить его тип ключа с std::string:

template<class T, class C>
T get_member_type(T C::*);

template<class Base>
struct foo{
  template<class I, std::size_t Len>
  constexpr const foo<Base> s(I, char const (&section_name)[Len]) const {
    using M=decltype(get_member_type(I::value));
    static_assert(std::is_same<typename M::key_type, std::string>{});
    return *this;
  }
};

#define CONST(e) std::integral_constant<decltype(e), e>

struct my_struct {
  std::map<std::string, int> section;
  constexpr static auto bar = foo<my_struct>().s(CONST(&my_struct::section){}, "hi");
};

Ошибка, которую вы получаете вВаше редактирование связано с тем, что вы не можете частично специализировать шаблоны функций.К счастью, вы можете расширить код в моем ответе выше, чтобы перегрузить его в зависимости от типа ключа с диспетчеризацией тегов:

template<class Base>
struct foo{
  template<class M>
  using get_key_type = typename M::key_type;
  template<class I>
  using get_member_type = decltype(::get_member_type(I::value));

  template<class I, std::size_t Len>
  constexpr auto s(I, char const (&section_name)[Len]) const {
    return s(I{}, section_name, 
      std::is_same<get_key_type<get_member_type<I>>, std::string>{}
    );
  }
private:
  template<class I, std::size_t Len>
  constexpr const auto s(I, char const (&section_name)[Len], std::false_type) const {
    return *this;
  }

  template<class I, std::size_t Len>
  constexpr const auto s(I, char const (&section_name)[Len], std::true_type) const {
    return *this;
  }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...