假设你有这样的东西:
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");
关于c++ - 你能在 C++ 元编程中的 "hop"之间 "linked classes"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72875270/