在嵌套类型名上制作模板的通用方法

Tom*_*rik 2 c++ templates c++17

动机:

给定一个类层次结构(并使用带有 mixin tp.classes 的 CRTP 技术,但为了简单起见,这里省略了),我想一般性地使用已知标识符来处理嵌套类型,但可能使用“未知”父类。

我的第一次(不成功)尝试的最小示例:

#include <type_traits>

using namespace std;

struct A {
    using Type_x = int;
    using Type_y = char;
};

struct B {
    using Type_x = float;
    using Type_y = double;
};

template <typename T> struct C {
    using Type_x = typename T::Type_x;
    using Type_y = typename T::Type_y;
};

// not possible
// template <typename T, typename U> using Tp_type = typename T::typename U;
//
// static_assert(is_same_v<C<A>::Type_x, Tp_type<C<A>, Type_x>>);
Run Code Online (Sandbox Code Playgroud)

我想出了一个解决方案,它看起来很实用,但不太漂亮。下面是一个示例,其中派生类还引入了进一步的嵌套类型,但仍然以相当通用的方式处理:

/// given the code above ...

struct None {};

constexpr int type_x_id = 1;
constexpr int type_y_id = 2;

template <typename T>
struct D1 : C<T> {
    using typename C<T>::Type_x;
    using typename C<T>::Type_y;

    template <int typeId>
        using Type = conditional_t<typeId == type_x_id, Type_x,
                     conditional_t<typeId == type_y_id, Type_y,
                     None>>;
};

constexpr int type_z_id = 3;

template <typename T>
struct D2 : D1<T> {
    using Type_z = long;

    template <int typeId>
        using Type = conditional_t<!is_same_v<typename D1<T>::template Type<typeId>, None>,
                                   typename D1<T>::template Type<typeId>,
                     conditional_t<typeId == type_z_id, Type_z,
                     None>>;
};

template <typename T, int typeId> using Tp_type = typename T::template Type<typeId>;
Run Code Online (Sandbox Code Playgroud)

使用/测试:

static_assert(is_same_v<D1<A>::Type_x, Tp_type<D1<A>, type_x_id>>);
static_assert(is_same_v<D1<A>::Type_y, Tp_type<D1<A>, type_y_id>>);
// static_assert(!is_same_v<D1<A>::Type_z, Tp_type<D1<A>, type_z_id>>);
static_assert(is_same_v<D2<A>::Type_x, Tp_type<D1<A>, type_x_id>>);
static_assert(is_same_v<D2<A>::Type_y, Tp_type<D1<A>, type_y_id>>);
static_assert(!is_same_v<D2<A>::Type_z, Tp_type<D1<A>, type_z_id>>);
static_assert(is_same_v<D1<A>::Type_x, Tp_type<D2<A>, type_x_id>>);
static_assert(is_same_v<D1<A>::Type_y, Tp_type<D2<A>, type_y_id>>);
// static_assert(!is_same_v<D1<A>::Type_z, Tp_type<D2<A>, type_z_id>>);
static_assert(is_same_v<D2<A>::Type_x, Tp_type<D2<A>, type_x_id>>);
static_assert(is_same_v<D2<A>::Type_y, Tp_type<D2<A>, type_y_id>>);
static_assert(is_same_v<D2<A>::Type_z, Tp_type<D2<A>, type_z_id>>);

static_assert(is_same_v<D1<B>::Type_x, Tp_type<D1<B>, type_x_id>>);
static_assert(is_same_v<D1<B>::Type_y, Tp_type<D1<B>, type_y_id>>);
// static_assert(!is_same_v<D1<B>::Type_z, Tp_type<D1<B>, type_z_id>>);
static_assert(is_same_v<D2<B>::Type_x, Tp_type<D1<B>, type_x_id>>);
static_assert(is_same_v<D2<B>::Type_y, Tp_type<D1<B>, type_y_id>>);
static_assert(!is_same_v<D2<B>::Type_z, Tp_type<D1<B>, type_z_id>>);
static_assert(is_same_v<D1<B>::Type_x, Tp_type<D2<B>, type_x_id>>);
static_assert(is_same_v<D1<B>::Type_y, Tp_type<D2<B>, type_y_id>>);
// static_assert(!is_same_v<D1<B>::Type_z, Tp_type<D2<B>, type_z_id>>);
static_assert(is_same_v<D2<B>::Type_x, Tp_type<D2<B>, type_x_id>>);
static_assert(is_same_v<D2<B>::Type_y, Tp_type<D2<B>, type_y_id>>);
static_assert(is_same_v<D2<B>::Type_z, Tp_type<D2<B>, type_z_id>>);

static_assert(!is_same_v<D1<A>::Type_x, Tp_type<D1<B>, type_x_id>>);
static_assert(!is_same_v<D1<A>::Type_y, Tp_type<D1<B>, type_y_id>>);
// static_assert(!is_same_v<D1<A>::Type_z, Tp_type<D1<B>, type_z_id>>);
static_assert(!is_same_v<D2<A>::Type_x, Tp_type<D1<B>, type_x_id>>);
static_assert(!is_same_v<D2<A>::Type_y, Tp_type<D1<B>, type_y_id>>);
static_assert(!is_same_v<D2<A>::Type_z, Tp_type<D1<B>, type_z_id>>);
static_assert(!is_same_v<D1<A>::Type_x, Tp_type<D2<B>, type_x_id>>);
static_assert(!is_same_v<D1<A>::Type_y, Tp_type<D2<B>, type_y_id>>);
// static_assert(!is_same_v<D1<A>::Type_z, Tp_type<D2<B>, type_z_id>>);
static_assert(!is_same_v<D2<A>::Type_x, Tp_type<D2<B>, type_x_id>>);
static_assert(!is_same_v<D2<A>::Type_y, Tp_type<D2<B>, type_y_id>>);
static_assert(is_same_v<D2<A>::Type_z, Tp_type<D2<B>, type_z_id>>);
Run Code Online (Sandbox Code Playgroud)

有更好的解决方案吗?例如,不需要Type每次出现新的嵌套类型标识符时都进行定义。

Yak*_*ont 5

如果不编写整个库或使用编译时反射(此时看起来像 ) ,则无法传递名称并基于它们查找类型。

但您希望能够在编译时传递标识符。你的int解决方案有点尴尬;我建议传递进行查找的模板:

template<class T>
using Type_x_t = typename T::Type_x;
template<class T>
using Type_y_t = typename T::Type_y;
Run Code Online (Sandbox Code Playgroud)

ETC

然后你可以这样做:

template <typename T, template<class...> class U_t>
using Tp_type_t = U_t<T>;

static_assert(
  std::is_same_v<D1<A>::Type_x, Tp_type_t<D1<A>, Type_x_t>);
);
Run Code Online (Sandbox Code Playgroud)

或者:

static_assert(
  std::is_same_v<D1<A>::Type_x, Type_x_t<D1<A>>);
);
Run Code Online (Sandbox Code Playgroud)

我们传递映射到Foo_t<>的模板,然后它充当子类型的“名称”。TT::Foo