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:
- The returned type (like
S1) is incomplete. - All type computation logic should be done with
if constexpr(in my problemTis pretty complicated and it is much easier to use nestedifs 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.)