获取给定结构的内部结构类型列表的类型特征

问题描述 投票:0回答:1

考虑以下代码:

#include <tuple>
#include <type_traits>

struct foo
{
    struct a {};
    struct b {};
    struct c {};
};

// we use here an hypothetical type trait 'get_struct_list_t'
using T = get_struct_list_t<foo>;

static_assert (std::is_same_v <T, std::tuple<foo::a, foo::b, foo::c>>);

int main () {}

问题:是否可以设计一个类型特征

get_struct_list_t
来返回给定结构的内部结构类型列表?

我认为在C++中这是不可能的,因为它需要具有一些反射功能,所以我的问题主要是为了确认这一点。

c++ reflection template-meta-programming type-traits
1个回答
0
投票

最初的问题没有对必须检索其类型列表的内部结构做出任何假设。

如果这些内部结构只保存类型信息(即没有数据成员),我们可以使用以下技巧:我们可以定义一个匿名结构的成员,而不是命名实例

struct a {};
,即。
struct {} a;
。现在的好处是我们可以从中获取类型信息,换句话说,我们可以使用一些
struct_to_tuple
机制来获取我们想要的东西。然而,对于最终用户来说,这个解决方案非常笨拙且具有误导性。这比日常使用更有趣......

这是整个示例。请注意,我在这里使用以下

gist 从结构中获取 std::tuple

#include <type_traits> #include <tuple> /////////////////////////////////////////////////////////////////////////////// // https://gist.github.com/utilForever/1a058050b8af3ef46b58bcfa01d5375d /////////////////////////////////////////////////////////////////////////////// template<class T, typename... Args> decltype(void(T{std::declval<Args>()...}), std::true_type()) test (int); template<class T, typename... Args> std::false_type test (...); template<class T, typename... Args> struct is_braces_constructible : decltype(test<T, Args...>(0)) {}; struct any_type { template<class T> constexpr operator T(); }; template<class T> auto to_tuple(T&& object) noexcept { using type = std::decay_t<T>; if constexpr(is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) { auto&& [p1, p2, p3, p4] = object; return std::make_tuple(p1, p2, p3, p4); } else if constexpr(is_braces_constructible<type, any_type, any_type, any_type>{}) { auto&& [p1, p2, p3] = object; return std::make_tuple(p1, p2, p3); } else if constexpr(is_braces_constructible<type, any_type, any_type>{}) { auto&& [p1, p2] = object; return std::make_tuple(p1, p2); } else if constexpr(is_braces_constructible<type, any_type>{}) { auto&& [p1] = object; return std::make_tuple(p1); } else { return std::make_tuple(); } } /////////////////////////////////////////////////////////////////////////////// // The definition of our trait /////////////////////////////////////////////////////////////////////////////// template<typename T> struct get_struct_list { using type = decltype (to_tuple (T{})); }; template<typename T> using get_struct_list_t = typename get_struct_list<T>::type; //////////////////////////////////////////////////////////// // A testing struct //////////////////////////////////////////////////////////// struct foo { // the 'inversion' trick is here // -> use members of anonymous struct instead of named structs struct { using type=int; } a; // instead of struct a { using type=int; }; struct { using type=char; } b; struct { using type=float; } c; }; using T = get_struct_list_t<foo>; static_assert (std::is_same_v <std::tuple_element_t<0,T>::type, int >); static_assert (std::is_same_v <std::tuple_element_t<1,T>::type, char >); static_assert (std::is_same_v <std::tuple_element_t<2,T>::type, float>); int main () {}
    
© www.soinside.com 2019 - 2024. All rights reserved.