一、介绍
一般人可能没怎么听说过元编程,但是大多搞程序的都听说过元数据,元数据是表示数据的数据,那么元编程(元程序)就可以推广过来,元编程(元程序)是表示程序的程序。用英语来表示“a program about program”。可能很多人对此表示很陌生,没有接触过它,确实是这样。因为他的应用场景一般在普通的编程领域很少遇到,即使遇到,也可能是当成一种特例来使用。其实,如果接触过编译器方面的知识,可能就会明白它的含义。因为,编译器就是用来描述编程语言的语言,其实就是一种方法规则解析器。通过它来描述具体的c++语言来编译成可执行的二进制程序。
没怎么见过元编程,不代表元编程的重要性低。其实,元编程在基础库和科学计算上,应用还是相当广泛的。另外,在c++11以后,数据类型的控制和计算也都引入了大量的模板元编程,这都是需要同学们引起重视的。做为中级篇,这里只是引出开头,不做过多详细的阐述和说明。
既然说到了它很重要,那么它有什么好处呢?首先,元编程可以在编译器进行运算,降低运行期的消耗(这个得具体问题具体分析),另外一个就是应用在一些基础的数据解析和运算上,它的优势在于形成统一的解决问题的方法,容易维护和理解。最后,它可以有类似模板的功能,通过一定的技巧来实现固定规则的代码变化(或者说就是生成代码)。
通过上述的分析也就可以看出来,元编程一般应用在解析器和基础组件(库),通用计算模块和SNAFE检查。
二、初步的例程
按照老规矩,先看一个简单的例程:
#include <iostream>
template<int N, int U>
struct Meta
{
static const int result = N * N - U;
};
int main()
{
std::cout << Meta<2, 3>::result << std::endl;
std::cout << "Hello World!\n";
}
在模板的元编程中,能够使用的元素还是比较少的,一般来说只能使用枚举体和静态变量来处理整数,使用typedef和 using定义元数据。一些简单的逻辑,比如判断语句(if-else)就不无法直接在里面进行操作了,只能使用模板的萃取(traits)技术来实现。
在学习c++模板时,接触过萃取技术,其中类型萃取(type-traits)是最常用的。在元编程,也离不开他,其实,在c++11之后引进的大量的模板元编程库都是进行类型控制的,其中底层就离不开这个类型萃取。在c++17中提供了一个std::optional,看一下例程:
#include <iostream>
#include <optional>
std::optional<unsigned> TestOptional(std::string s)
{
std::cout << s << std::endl;
return 0;
}
int main()
{
std::string s = "";
std::optional<unsigned> opt = TestOptional(s);
if (opt.has_value())
{
std::cout << "value is:" << opt.value() << std::endl;
}
}
关于萃取的更多说明会在高级篇中一一分析。这里只是一个抛砖引玉的作用。
三、总结
元编程虽然有着不少的优势,并且在新的c++标准中有扩大应用的趋势,但是不可否认的是,其缺点较之模板还要增加一些。除了代码膨胀、不易于调试和复杂等特点外,在处理实例化时,也是一个让人头疼的问题。经常会出现这样那样的问题。所以c++20中引入了std::concept(概念)这个概念(有点拗口),通过概念来解决参数的限制和检查。技术的进步也一定会带来一些技术的复杂性和副产品,看主流吧。