Получить тип из варианта во время компиляции - PullRequest
0 голосов
/ 26 марта 2019

Мне нужно выполнить проверку типов на предмет того, может ли тип варианта содержать тип во время компиляции.

Я преобразую перечисление и строку в вариант, но я хочу, чтобы библиотека была совместима спредоставленный пользователем вариант (для поддерживаемых типов).Поэтому у меня есть параметр шаблона CustomVariant для представления варианта над подмножеством поддерживаемых типов AlphaBeta, Gamma, Delta и Epsilon.Я хотел бы вернуть std::nullopt, если не могу создать правильный вариант.

template <typename CustomVariant>
std::optional<CustomVariant> AsCustomVariant(LargeEnum type, const std::string& name) {
  case LargeEnum::ALPHA:
  case LargeEnum::BETA:
    return ConvertAlphaBeta(name);

  case LargeEnum::GAMMA:
    return ConvertGamma(name);

  case LargeEnum::DELTA:
    return ConvertDelta(name);

  case LargeEnum::EPSILON:
    return ConvertEpsilon(name);

  default:
    return std::nullopt;
}

Идея состоит в том, чтобы использовать какую-то магию шаблонов, которая может сделать что-то вроде:

if (std::type_can_convert<CustomVariant, Gamma>) {
  return ConvertGamma(name);
} else {
  return std::nullopt;
}

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

С c ++ 17 (я знаю, что он помечен с ++ 11), это очень просто - вам даже не нужно ничего делать:

#include <variant>
#include <type_traits>
#include <string>

using namespace std;

int main() {

    // this works, as expected
    if constexpr(is_constructible_v<variant<int>, double>) {
        // this will run
    }

    // this is fine - it just won't happen, 
    if constexpr(is_constructible_v<variant<int>, string>) {
        // this won't run
    } else {
        // this will run
    }
    // but obviously the assignment of a string into that variant doesn't work...
    variant<int> vi="asdf"s;
}

https://godbolt.org/z/I-wJU1

1 голос
/ 26 марта 2019

Сначала я бы сделал это:

template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};

template<class...Ts>using one_tag_of=std::variant<tag_t<Ts>...>;

using which_type=one_tag_of<AlphaBeta, Gamma, Delta /* etc */>;

which_type GetType(LargeEnum e){
  switch (e){
    case LargeEnum::Alpha:
    case LargeEnum::Beta: return tag<AlphaBeta>;
    // etc
  }
}

Теперь мы делаем это:

template <typename CustomVariant>
std::optional<CustomVariant> AsCustomVariant(LargeEnum type, const std::string& name) {
  auto which = GetType(type);
  return std::visit( [&name](auto tag)->std::optional<CustomVariant>{
    using type=typename decltype(tag)::type;
    if constexpr (std::is_convertible<CustomVariant, type>{})
      return MakeFromString( tag, name );
    return std::nullopt;
  }, which );
}

это оставляет MakeFromString.

Запишите такие перегрузки:

inline Delta MakeFromString(tag_t<Delta>, std::string const& name){ return ConvertDelta(name); }

примечание, а не специализации. Просто перегружает.

...