Using decltype(func<T>()) to compute a type that is incomplete

Viewed 109

Suppose I have the following code to compute a new type based on the given one:

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;
}

So far so good. Suppose now that I want to use a function to do the same job with the following constraints:

  1. The returned type (like S1) is incomplete.
  2. All type computation logic should be done with if constexpr (in my problem T is pretty complicated and it is much easier to use nested ifs than SFINAE).

This code

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>());

won't work because S1 and S2 are incomplete. To circumvent the problem, I can use a type_identity "wrapper":

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;

or a pointer:

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>())>;

What are the alternative ways to do it? (I would even say "better", but I'm afraid of being accused of asking an opinion-based question.)

0 Answers
Related