【发布时间】:2020-08-18 04:16:08
【问题描述】:
所以我最近发现 C++ 确实有反射,只是没有人发生,甚至 C++ 委员会都不知道,直到一位俄罗斯天才打开了通往不可能调试世界的大门。
带着这个序言,让我们来看看这个危害人类罪:
template <typename T, typename D = decltype(T().field)>
struct foo { bool b = true; };
template <typename T>
struct foo<T, void> { bool b = false; };
template <typename T>
constexpr bool HasField() { return foo<T>().b; }
编译并且可以工作。给定任何成员不是私有的类型,您可以检查该类型是否定义了一个名为 field 的文件。
但是,这会迫使您为要检查的每个字段编写该模式。它会起作用,但它会在任何地方添加一堆复制意大利面并使代码变得丑陋(并不是说即使你复制一次代码也会很漂亮)。
因此,出于纯粹的好奇心,我试图思考进行通用 POD 字段检查的最不恶心的方式。
我的一个想法是这样的:
#define HAS_FIELD(field) \
template <typename T, typename D = decltype(T().#field)> \
struct foo_#field { bool b = true; }; \
\
template <typename T> \
struct foo_#field<T, void> { bool b = false; }; \
\
template <typename T> \
constexpr bool HasField#field() { return foo<T>().b; }
这至少减少了一个宏调用必须写入的行数。但我不满意,我想看看我们是否可以使用模板和宏来获得一个可以在任何地方调用的函数,而无需在前面加上宏。
即我们希望能够做到(或类似):
struct POD {/**/};
int main() { HasField(POD, FieldName); }
请注意,目前这几乎是可能的:
struct POD {/**/};
HAS_FIELD(FieldName)
int main() { HasFieldFieldName<POD>(); }
再次强调,这不是一个好主意,而是我们能否做到。
【问题讨论】:
-
你想了解concepts。这不是反射。
-
你如何定义反射?它是对结构领域的元分析,也就是检查,这是反射的特征之一。这不是你可以用这种形式的元编程做的唯一事情,你可以计算结构中的所有字段,将结构一般地转换为元组,获取每个字段的大小......但我离题了。另外我不确定概念在这里有什么帮助,重点是,上面的代码为您提供了一个布尔值,您可以在运行时使用它来执行逻辑。就像在字段存在时调用函数一样。
-
@Makogan 反射定义的一个关键部分是它发生在运行时。没有编译时反射这样的东西。我们这里有的是编译时内省,而不是反射。
-
查看 requires-expression。
-
这不是反射,因为它不允许您执行反射在本机支持反射的语言中所做的事情。它可以让你做非常非常非常小的一部分。这是反射的苍白阴影(请原谅双关语)。
标签: c++ templates macros template-meta-programming