LINUX.ORG.RU

get_if для variant как метод класса

 


1

2

Собственно использую https://github.com/mpark/variant в C++14, single header версию.

Очень неудобно, что фактически все методы - глобальные:

mpark::get_if<State1>(&m_state)
// vs
m_state.get_if<State1>()

Вопрос в том, как добавить в эту либу get_if (и holds_alternative) как методы класса? Только для типов. Взятие по индексу не нужно.

Там внутри такой адок, что я боюсь вообще что-либо трогать. Типа:

template <
        typename Arg,
        typename Decayed = lib::decay_t<Arg>,
        lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0,
        lib::enable_if_t<!detail::is_in_place_index<Decayed>::value, int> = 0,
        lib::enable_if_t<!detail::is_in_place_type<Decayed>::value, int> = 0,
        std::size_t I = detail::best_match<Arg, Ts...>::value,
        typename T = lib::type_pack_element_t<I, Ts...>,
        lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0>
    inline constexpr variant(Arg &&arg) noexcept(
        std::is_nothrow_constructible<T, Arg>::value)
        : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) {}

Или проще тупо враппер сделать? Но там тоже тонну шаблонов придётся писать - не осилю.

★★★★★

Очень неудобно, что фактически все методы - глобальные

Так это и в C++17 так.

Или проще тупо враппер сделать?

Вокруг чего вы собрались wrapper делать? Вокруг variant-а?

eao197 ★★★★★
()
Ответ на: комментарий от bigov

Потому, что недоступна. И её использование мне не поможет.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

И мне это дико неудобно.

Это дело привычки. Тем более, что такие либы эмулируют стандарт для старых компиляторов.

Так вокруг чего вы хотите враппер создать?

eao197 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Тогда вам нужно будет делать наследование от этого variant-а. А что там с шаблонами страшного? Вроде как все должно быть более менее тривиально:

template<typename... Types>
class my_variant : public third_party::variant<Types...> {
... 
  using base_type = third_party::variant<Types...>;
public:
  using base_type::base_type;

  template<typename T>
  auto get_if() noexcept { return third_party::get_if<T>(this); }
  ...
};

PS. С расположением многоточий мог напутать.

eao197 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Ну вы попробуйте, это же набросок, может там какие-то подводные камни встретятся.

eao197 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Основной геморрой о работе с типами (для соответствия поведению, указанному в стандарте), thirdparty::variant всё равно берет на себя, поэтому можно ограничится простым вариадик темплейтом, как eao197 прописал, а все эти decay и прочее SFINAE останутся бременем самого верианта.

Однако! Неспроста variant в шаблоне приведенного конструктора проверяет подаваемый тип на variant и «выключается» при совпадении - иначе можно «не попасть» в настоящий конструктор копирования и перемещения. Это особенно стремно для any, где автоматическая генерация подобного конструктора без проверки привела бы к рекурсии.

Вобщем я вот о чем - _наследоваться_ от варианта и наследовать так же его конструкторы может быть не очень хорошая идея. Я бы заменил здесь наследование на более безопасное, но менее удобное делегирование.

yoghurt ★★★★★
()

Вопрос в том, как добавить в эту либу get_if (и holds_alternative) как методы класса?

Функции типа get<T>() реализованны в виде свободных, а не методов, потому что вызов таких методов в шаблонном контексте требует специального синтаксиса:

template <typename T>
auto some_foo(mpark::variant<int, double, OtherType> const & v)
{
    v.template get_if<T>(v);  // нужно писать template
    mpark::get_if<T>(v);      // не нужно писать template
}
rupert ★★★★★
()
Ответ на: комментарий от rupert

Почему так сделано я знаю. Но это не удобно.

RazrFalcon ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.