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每次出现新的嵌套类型标识符时都进行定义。
如果不编写整个库或使用编译时反射(此时看起来像c++26 ) ,则无法传递名称并基于它们查找类型。
但您希望能够在编译时传递标识符。你的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