C ++模板元编程,成员变量的数量?

时间:2010-04-07 03:41:01

标签: c++ templates metaprogramming

在C ++中是否可以确定泛型类中的变量/字段数? 例如

// suppose I need metaclass number_members determines number of members

struct example { int i, j; };
assert(number_members<example>::value==2);

我查看了mpl,但找不到实施。

感谢。

4 个答案:

答案 0 :(得分:7)

没有。 C ++不提供对结构的一般内省。

您可以尝试使用C ++0x std::tuple,它具有一般POD struct的一些功能。或者,尝试从Boost MPL库中推出自己的库。如果您刚刚开始使用C ++,那将会有点提升。

答案 1 :(得分:1)

没有。不幸的是,C ++没有内置的这种内省。但是,通过一些额外的预处理,例如QtMeta Object Compiler (moc),您可以实现类似的功能...... QMetaObject类提供propertyCount();但是,你的类需要从QObject继承,使用Q_OBJECT宏,并注册所有工作的属性......所以,简而言之,它不是自动的。

答案 2 :(得分:1)

你不能直接这样做。那么显而易见的问题是,你正在努力实现的目标 - 你可以做你需要做的事情,但做到这一点的方式可能会有所不同。

答案 3 :(得分:1)

是的,但有限制。您可以在mattkretz/virtools找到我的实现。它需要C ++ 20,因为它使用了概念。原则上,您可以使用PRIORITY_HIGH重写它,从而使其与C ++ 17一起使用。 Live example

这里的主要思想是将可以检查的类型集限制为在单个基类中或仅在派生类中(但仍允许空基类)带有非静态数据成员的聚合。这与结构化绑定所施加的限制相同。然后,您知道类型public class MainActivity extends AppCompatActivity { private static final String CHANNEL_ID = "12345"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); createNotificationChannel(); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("My notification") .setContentText("Much longer text that cannot fit one line...") .setStyle(new NotificationCompat.BigTextStyle() .bigText("Much longer text that cannot fit one line...")) .setPriority(NotificationCompat.PRIORITY_MAX); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); // notificationId is a unique int for each notification that you must define int notificationId = 5433; notificationManager.notify(notificationId, builder.build()); } private void createNotificationChannel() { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is new and not in the support library CharSequence name = "fdsajfds"; int importance = NotificationManager.IMPORTANCE_HIGH; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); // Register the channel with the system; you can't change the importance // or other notification behaviors after this NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } 是否具有例如如果enable_if是有效的表达式(即无替换失败),则为3个(或更多)成员。 T在哪里:

T{anything_but_base_of<T>(), anything_but_base_of<T>(), anything_but_base_of<T>()}

由于聚合初始化允许指定的初始化次数少于聚合成员所需要测试的初始化次数,因此成员必须从上限开始进行测试,然后递归递减至0,直到找到可能的聚合初始化为止。我的实现使用的解构测试实际上不是SFINAE条件,而是会产生硬错误。因此,您也可以删除该代码,进行实现:

anything_but_base_of

最后,我们需要一个合理的上限。对于位域的情况,正确的上限是template <class Struct> struct anything_but_base_of { template <class T> requires(!std::is_base_of_v<T, Struct>) operator T(); }; ,在该位域中,每个非静态数据成员占用一个位,并且整个结构不包含填充。考虑到使用正确上限的编译时间成本,我选择了一种更明智的启发式方法:namespace detail { template <class Struct> struct any_empty_base_of { template <class T> requires(std::is_base_of_v<T, Struct> && std::is_empty_v<T>) operator T(); }; template <class T, size_t... Indexes> concept brace_constructible = requires { T{((void)Indexes, anything_but_base_of<T>())...}; } || requires { T{any_empty_base_of<T>(), ((void)Indexes, anything_but_base_of<T>())...}; } || requires { T{any_empty_base_of<T>(), any_empty_base_of<T>(), ((void)Indexes, anything_but_base_of<T>())...}; } || requires { T{any_empty_base_of<T>(), any_empty_base_of<T>(), any_empty_base_of<T>(), ((void)Indexes, anything_but_base_of<T>())...}; }; template <class T, size_t... Indexes> requires brace_constructible<T, Indexes...> constexpr size_t struct_size(std::index_sequence<Indexes...>) { return sizeof...(Indexes); } template <class T> requires requires { T{}; } constexpr size_t struct_size(std::index_sequence<>) { static_assert(std::is_empty_v<T>, "Increase MaxSize on your struct_size call. (Or you found a bug)"); return 0; } template <class T, size_t I0, size_t... Indexes> requires(!brace_constructible<T, I0, Indexes...>) constexpr size_t struct_size(std::index_sequence<I0, Indexes...>) { // recurse with one less initializer return struct_size<T>(std::index_sequence<Indexes...>()); } } // namespace detail

sizeof(T) * CHAR_BIT