Мне нужно определить класс шаблона A, который имеет вложенный тип в соответствии с вложенным типом в аргументе шаблона. Как это:
template<typename Container>
class A
{
public:
using NestedType = if (Container has nested type Container::NestedTypeA)
{
Container::NestedTypeA;
}
else if (Container has nested type Container::NestedTypeB)
{
Container::NestedTypeB;
}
else
{
Container::NestedTypeC;
}
};
Как реализовать это с помощью объявления? Или есть другой способ добиться того же эффекта?
Спасибо за ответы 康桓瑋 и Jarod42. Но оба ответа используют концепции С++ 20. Как насчет использования С++ 17 максимум?
@Jarod42: Jarod42: Это не позволяет вам называть несуществующие типы в «ветвях», которые не используются. Вы должны поместить имена в тело специализации SFINAE-d.
@DavisHerring: с чертами для задержки создания экземпляра это может сработать (см. Мой ответ).
В C++20 вы можете просто использовать понятия
template<typename Container>
struct B { };
template<typename Container>
requires requires { typename Container::NestedTypeA; }
struct B<Container> {
using NestedType = typename Container::NestedTypeA;
};
template<typename Container>
requires requires { typename Container::NestedTypeB; } &&
(!requires { typename Container::NestedTypeA; })
struct B<Container> {
using NestedType = typename Container::NestedTypeB;
};
template<typename Container>
requires requires { typename Container::NestedTypeC; } &&
(!requires { typename Container::NestedTypeA; }) &&
(!requires { typename Container::NestedTypeB; })
struct B<Container> {
using NestedType = typename Container::NestedTypeC;
};
template<typename Container>
class A : public B<Container> {};
В C++17 вы можете использовать std::void_t
для определения правильности типов членов.
#include <type_traits>
template<typename Container, typename = void>
constexpr bool HasNestedTypeA = false;
template<typename Container>
constexpr bool HasNestedTypeA<
Container, std::void_t<typename Container::NestedTypeA>> = true;
template<typename Container, typename = void>
constexpr bool HasNestedTypeB = false;
template<typename Container>
constexpr bool HasNestedTypeB<
Container, std::void_t<typename Container::NestedTypeB>> = true;
template<typename Container, typename = void>
constexpr bool HasNestedTypeC = false;
template<typename Container>
constexpr bool HasNestedTypeC<
Container, std::void_t<typename Container::NestedTypeC>> = true;
template<
typename Container,
bool = HasNestedTypeA<Container>,
bool = HasNestedTypeB<Container>,
bool = HasNestedTypeC<Container>>
struct B { };
template<typename Container>
struct B<Container, false, false, false> {};
template<typename Container, bool B1, bool B2>
struct B<Container, true, B1, B2> {
using NestedType = typename Container::NestedTypeA;
};
template<typename Container, bool B1>
struct B<Container, false, true, B1> {
using NestedType = typename Container::NestedTypeB;
};
template<typename Container>
struct B<Container, false, false, true> {
using NestedType = typename Container::NestedTypeC;
};
template<typename Container>
class A : public B<Container> {};
СПАСИБО. Как это сделать с С++ 17?
С std::conditional_t
и соответствующими чертами вы можете сделать что-то вроде:
template <typename Container>
struct NestedTypeA
{
using type = typename Container::NestedTypeA;
};
template <typename Container>
struct NestedTypeB
{
using type = typename Container::NestedTypeB;
};
template <typename Container>
struct NestedTypeC
{
using type = typename Container::NestedTypeC;
};
template <typename T>
constexpr bool hasNestedTypeA = requires{ typename T::NestedTypeA; };
template <typename T>
constexpr bool hasNestedTypeB = requires{ typename T::NestedTypeB; };
template<typename Container>
class A
{
public:
using NestedType = typename std::conditional_t<
hasNestedTypeA<Container>,
NestedTypeA<Container>,
std::conditional_t<hasNestedTypeB<Container>,
NestedTypeB<Container>,
NestedTypeC<Container>>
>::type;
};
Кажется, что это имеет симметрию между NestedTypeA
и NestedTypeB
, постановка задачи указывает на предпочтение NestedTypeA
@BenVoigt: Действительно, исправил мою первоначальную идею с std::conditional
.
СПАСИБО. Как это сделать с С++ 17?
@byhc: Обнаружение черт подтипа можно выполнить с помощью std::void_t
и активатора вместо C++ 20 requires
: Демо.
Передайте «вложенный тип» в качестве второго аргумента.