Использование decltype (func <T>()) для вычисления неполного типа - PullRequest
4 голосов
/ 04 июня 2019

Предположим, у меня есть следующий код для вычисления нового типа на основе заданного:

struct S1;
struct S2;

// S1 and S2 are incomplete here

template<typename> struct get_type {
    using Type = S2;
};

template<> struct get_type<int> {
    using Type = S1;
};

template<typename T> using Get_type = typename get_type<T>::Type;

struct S1 {};
struct S2 {};

void foo() {
   Get_type<int> s1;
   Get_type<long> s2;
}

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

  1. Возвращаемый тип (например, S1) является неполным.
  2. Логика вычислений всех типовдолжно быть сделано с if constexpr (в моей задаче T довольно сложно и гораздо проще использовать вложенные if s, чем SFINAE).

Этот код

template<typename T> auto get_type() {
    if constexpr (std::is_same_v<T, int>)
        return S1{};
    else
        return S2{};
}

template<typename T> using Get_type = decltype(get_type<T>());

не будет работать, потому что S1 и S2 не завершены.Чтобы обойти проблему, я могу использовать type_identity «обертку»:

template<class T> struct type_identity {
    using Type = T;
};

template<typename T> auto get_type() {
    if constexpr (std::is_same_v<T, int>)
        return type_identity<S1>{};
    else
        return type_identity<S2>{};
}

template<typename T> using Get_type = typename decltype(get_type<T>())::Type;

или указатель:

template<typename T> auto get_type() {
    if constexpr (std::is_same_v<T, int>)
        return static_cast<S1*>(nullptr);
    else
        return static_cast<S2*>(nullptr);
}

template<typename T> using Get_type = std::remove_pointer_t<decltype(get_type<T>())>;

Каковы альтернативные способы сделать это?(Я бы даже сказал «лучше», но я боюсь, что меня обвинят в том, что я задавал вопрос, основанный на мнении.)

...