byhc
byhc

Reputation: 183

conditional type define in c++?

I need to define a template class A, which has a nested type according to nested type in template argument. Like this:

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

How to implement this using declaration? Or is there another way to acheive the same effect?


Thanks the answers by 康桓瑋 and Jarod42. But the two answers both use C++20's concepts. How about use C++17 at most?

Upvotes: 2

Views: 377

Answers (2)

康桓瑋
康桓瑋

Reputation: 42756

In C++20, you can just use concepts

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

Demo

In C++17, you can use std::void_t to detect the validity of member types.

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

Demo

Upvotes: 2

Jarod42
Jarod42

Reputation: 217245

With std::conditional_t and appropriate traits, you might do something like:

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

Demo

Upvotes: 1

Related Questions