c++ - 你能在 C++ 元编程中的 "hop"之间 "linked classes"吗?

标签 c++ templates template-meta-programming

假设你有这样的东西:

template<class D>
class HasDef {
public:
     typedef D Def;
};

class A : public HasDef<class B> {};
class B : public HasDef<class C> {};
class C {};

所以它就像一个“元编程链表”,带有类型链接,通过包含的 typedef Def .现在我想制作一个模板“叶子”,当应用于 A ,点击链接以获取 C :

void f() {
     Leaf<A>::type v; // has type C
}

甚至有可能做到这一点吗?我用 std::compare 尝试了一些方法和类似的,但没有一个是有效的代码:一切似乎都遇到了C的问题没有Def typedef,否则类型 Leaf<>当进行内部递归“调用”时,它本身是不完整的,因此它(或其内部类型 type )无法被引用。

FWIW,我想要这个的原因是为了制作一个“分层状态机”,其中 Def表示层次结构中每个状态的默认状态,并且更详细一点,这似乎为它提供了相当整洁和干净的“用户界面语法”。

最佳答案

我不太喜欢现代代码中的 f(...),因此我的版本使用 C++17 中的 void_t:

#include <type_traits>

template<class D>
struct HasDef {

     typedef D Def;
};

struct A : HasDef<class B> {};
struct B : HasDef<class C> {};
struct C {};


template <typename T, typename=void>
struct DefPresent : std::false_type{};

template <typename T>
struct DefPresent<T, std::void_t<typename T::Def>> : std::true_type{};


template<typename T, bool deeper = DefPresent<T>::value>
struct Leaf
{
    using Type = typename Leaf<typename T::Def>::Type;
};

template<typename T>
struct Leaf<T, false >
{
    typedef T Type;
};



static_assert(std::is_same<typename Leaf<C>::Type, C>::value, "C");
static_assert(std::is_same<typename Leaf<B>::Type, C>::value, "B");
static_assert(std::is_same<typename Leaf<A>::Type, C>::value, "A");

https://godbolt.org/z/5h5rfe81o

编辑:仅出于完整性考虑,使用概念的 2 个 C++20 变体。在 GCC 10 上测试

#include <type_traits>
#include <concepts>

template<class D>
struct HasDef {
     typedef D Def;
};

struct A : HasDef<class B> {};
struct B : HasDef<class C> {};
struct C {};

template <typename T>
concept DefPresent = requires(T a)
{
    typename T::Def;
};

template<typename T>
struct Leaf
{
    using Type = T;
};


template<typename T>
    requires DefPresent<T>
struct Leaf<T>
{
    using Type = Leaf<typename T::Def>::Type;
};


static_assert(std::is_same_v<typename Leaf<C>::Type, C>, "C");
static_assert(std::is_same_v<typename Leaf<B>::Type, C>, "B");
static_assert(std::is_same_v<typename Leaf<A>::Type, C>, "A");


template<typename T>
struct Leaf2
{
    template <typename M>
    static M test(M&&);

    template <DefPresent M>
    static auto test(M&&) -> typename Leaf2<typename M::Def>::Type;

    using Type = decltype(test(std::declval<T>()));
};

static_assert(std::is_same<typename Leaf2<C>::Type, C>::value, "C");
static_assert(std::is_same<typename Leaf2<B>::Type, C>::value, "B");
static_assert(std::is_same<typename Leaf2<A>::Type, C>::value, "A");

https://godbolt.org/z/vcqEaPrja

关于c++ - 你能在 C++ 元编程中的 "hop"之间 "linked classes"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72875270/

相关文章:

c++ - 在函数模板的声明部分中定义时,对任意类型属性的函数重载失败

c++ - 条件类型别名定义

c++ - 根据某些条件在编译时生成字符串

c++ - 嵌入 luajit undefined reference

c++ - 如何在一行中使用三元运算符来做到这一点?

c++ - 使用 printf 和 cout 获得不同的输出 - C++

c++ - 在 Linsched 中使用 task_struct

c++ - 避免在用户定义的模板特化中重复

c++ - 访问公共(public)继承模板数据成员

c++ - 无参数可变参数模板的模糊重载