Предположим, у меня есть следующий код для вычисления нового типа на основе заданного:
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;
}
Пока все хорошо.Предположим теперь, что я хочу использовать функцию для выполнения той же работы со следующими ограничениями:
- Возвращаемый тип (например,
S1
) является неполным. - Логика вычислений всех типовдолжно быть сделано с
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>())>;
Каковы альтернативные способы сделать это?(Я бы даже сказал «лучше», но я боюсь, что меня обвинят в том, что я задавал вопрос, основанный на мнении.)