我花了一天时间阅读笔记并观看关于boost :: fusion的视频,我真的没有得到一些方面。
以boost::fusion::has_key<S>
函数为例。在boost :: fusion中有这个的目的是什么?我们是否只是尝试在编译时尽可能多地进行编程?所以几乎任何boost::fusion
函数都与运行时版本相同,除了它现在在编译时评估? (我们假设在编译时做得更多很好吗?)。
与boost :: fusion相关,我也有点困惑为什么元函数总是返回类型。这是为什么?
答案 0 :(得分:4)
另一种看待boost :: fusion的方法是将其视为“穷人内省”库。 boost :: fusion的最初动机来自boost :: spirit解析器/生成器框架的方向,特别是需要支持所谓的“解析器属性”。
想象一下,你有一个要解析的CSV字符串:
aaaa,1.1
这个字符串解析的类型,可以描述为“字符串和双元组”。我们可以在“普通”C ++中定义这样的元组,使用旧学校结构(struct { string a; double b; }
或更新tuple<string, double>
)。我们唯一遗漏的是某种适配器,它允许将任意组合的元组(以及其他一些类型)传递给统一的解析器接口,并期望它能够理解它而不传递任何带外信息(例如字符串)解析scanf使用的模板。
这就是boost :: fusion发挥作用的地方。构建“融合序列”最直接的方法是调整正常结构:
struct a {
string s;
double d;
};
BOOST_FUSION_ADAPT_STRUCT(a, (string, s)(double, d))
“ADAPT_STRUCT”宏为解析器框架(在此示例中)添加了必要的信息,以便能够“迭代”struct a
成员以调整以下问题:
我刚刚解析了一个字符串。我可以将其分配给struct a
的第一个成员吗?
我刚刚解析了一个双。我可以将其分配给struct a
的第二位成员吗?
struct a
中是否有其他成员或我应该停止解析?
显然,这个基本的例子可以进一步扩展(和boost :: fusion提供的功能)来解决更复杂的情况:
变体 - 假设解析器可能遇到sting或double,并希望将其分配给struct a
的正确成员。 BOOST_FUSION_ADAPT_ASSOC_STRUCT
拯救了(现在我们的解析器可以提出诸如“struct a
的哪个成员是double类型的问题”。
转换 - 我们的解析器可以设计为接受某些类型作为参数,但其余的程序已经发生了很大的变化。然而,融合元功能可以方便地用于使新类型适应旧的现实(反之亦然)。
boost :: fusion功能的其余部分自然遵循上述基础知识。当需要将“松散的IO数据”转换为强类型/结构化数据C ++程序进行操作(如果效率受到关注)时,融合真的很闪耀。它是spirit :: qi和spirit :: karma背后的促成因素,它是一个如此高效(可能是最快)的I / O框架。
答案 1 :(得分:2)
Fusion是编译时和运行时容器和算法之间的桥梁。您可能想也可能不希望将某些处理工作转移到编译时,但如果您确实想要,那么Fusion可能会有所帮助。虽然我可能错了,但我认为它没有特定的宣言可以尽可能多地转移到编译时间。
元函数返回类型,因为模板元编程不是故意发明的。事实上,C ++模板可以被用作编译时编程语言或多或少。元函数是从模板参数到模板实例化的映射。从C ++ 03开始,有两种模板(类和函数),因此元函数必须“返回”类或函数。类比函数更有用,因为您可以将值等放在它们的静态数据成员中。
C ++ 11增加了另一种模板(对于typedef),但这与元编程无关。更重要的是,对于编译时编程,C ++ 11增加了constexpr
个函数。它们是为此目的而设计的,它们像普通函数一样返回值。当然,它们的输入不是类型,因此它们不能以模板的方式从类型映射到其他类型。所以从这个意义上说,他们缺乏元编程的“元”部分。它们只是“正常”编译时评估正常的C ++函数,而不是元函数。