C++惯用法:metafunction(元函数)

本文深入探讨了C++中的元函数,一种在编译期执行的函数,它们能够进行类型和常量计算。元函数分为type型和value型,前者用于类型计算,后者用于常量计算。元函数可以有多个返回值,甚至可以作为类的成员。此外,还介绍了高阶元函数,即接受其他元函数作为参数的元函数。元函数与运行期函数相比,具有无副作用、可返回多个值等特性。
摘要由CSDN通过智能技术生成

Metafunction: compile-time analogs of runtime functions

元函数:编译期的函数)

与运行期使用函数封装算法相对应,在C++编译期同样存在着封装算法进行编译期计算的需要。元函数(metafunction)便是实现这一需求的主要手段。元函数这一概念最早是由Boost.MPL类库提出并定义的。

作为在编译期进行计算的函数,元函数具有以下不同于运行期函数的特点:

  1. 输入(即参数)与输出(即返回值)均只包含两种类型:1)类型(名)2)整形常量。
  2. 可以返回一个或多个值,但不能没有返回值。
  3. 没有副作用:元函数在计算过程中既不能改变参数的值,也不具备“向控制台输入输出”之类的附加功能。

 

Kinds of Metafunction(元函数的分类)

按照返回值的类型来划分,元函数可分为以下两大类:  

1. type型元函数:返回类型(名)的元函数,也就是在编译期进行类型计算的元函数。

/****** 代码1 ******/
template <bool B, class L, class R>
struct IF
{
  typedef R type; 
};
 
template <class L, class R>
struct IF<true, L, R>
{
  typedef L type; 
};
 
IF<false, int, long>::type i; // is equivalent to long i;
IF<true,  int, long>::type i; // is equivalent to int i;

代码1定义了一个用于编译期类型选择的元函数IF,其实现依赖于类模板IF及其特化。
元函数IF的输入由3个模板参数构成:布尔类型B,类型名L,类型名R。
元函数IF的输出也就是需要返回的类型由typedef语句来定义,用于返回的类型名为type。
此处用于返回的类型名取名为type是为了遵循Boost.MPL类库的惯例。
若B的值为true,则元函数IF返回类型名L。(此分支由模板特化来定义)
若B的值为false,则元函数IF返回类型名R。(此分支由主模板来定义)
此处用struct关键字而不是class关键字来定义类模板的理由是:元函数IF的返回类型必须能被外界所访问,即type的访问权限必须是public。

2. value型元函数:返回整形常量的元函数,也就是在编译期进行常量计算的元函数。

/****** 代码2 ******/
template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
    //static const int value = N * Factorial<N - 1>::value;
};
 
template <>
struct Factorial<0> 
{
    enum { value = 1 };
    //static const int value = 1;
};
 
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

此码2定义了一个用于编译期计算阶乘的元函数Factorial,其实现依赖于类模板Factorial及其特化。
元函数Factorial的输入仅由1个模板参数构成:整数类型N。
元函数Factorial的输出也就是需要返回的整形常量由枚举或静态整形常量来定义,用于返回的常量名为value。
此处用于返回的常量名取名为value是为了遵循Boost.MPL类库的惯例。
若N的值为0,则元函数Factorial返回1。(此分支由模板特化来定义)
若N的值大于0,则元函数Factorial返回N*Factorial(N-1)。(此分支由主模板来定义)
此处用struct关键字而不是class关键字来定义类模板的理由是:元函数Factorial的返回值必须能被外界所访问,即value的访问权限必须是public。

 

Metafunction with "Multiple returns"(返回多值的元函数)

与运行期的函数有所不同,编译期所定义的元函数也可返回不止一个值。

Boost.MPL类库中的Integral Constant Wrapper(整形常量包装器)就属于这种返回多个类型名及整形常量的元函数。

/****** 代码3 ******/
template< bool x > struct bool_
{
    static bool const value = x;        
    typedef bool_<x> type;              
    typedef bool value_type;            
    operator bool() const { return x; } 
};

typedef bool_<false> false_;
typedef bool_<true> true_;

代码3(取自Boost.MPL类库)实现了一个布尔常量的包装器。
元函数bool_共有3个返回值。
1) 布尔值value。
2) 元函数自身的类型type。
3) 布尔值value的类型value_type。
根据元函数bool_的定义,不难推出以下等式为真。
1) false_::value == false。
2) true_::type::value == true。

 

Nullary Metafunction(零参数元函数)

元函数也可不用类模板而用普通的类来定义,此时元函数的参数个数为0,即元函数没有输入只有输出。

/****** 代码4 ******/
struct always_int
{
    typedef int type;
};

 

Member Metafunction(“成员”元函数)

元函数也可在类或类模板中定义,即元函数通过嵌套类的方式来实现。

这种元函数可称作“成员”元函数,也可称作“元方法”。

/****** 代码5 ******/
template <typename T>
struct value 
{
    BOOST_STATIC_ASSERT(
        mpl::not_<is_reference<T> >::value != 0);

    typedef mpl::false_ no_nullary;

    template <typename Env>
    struct result
    {
        typedef T type;
    };

    value(T const& arg)
        : val(arg) {}

    template <typename Env>
    T const&
    eval(Env const&) const
    {
        return val;
    }

    T val;
};

代码5(取自Boost.Pheonix类库)中,类模板value总共定义了2个元方法。
1) value型元方法no_nullary。
   这里no_nullary被定义为false_的同义词,false_的定义可参见示例代码3。
2) type型元方法result。

 

Higher-order Metafunction(高阶元函数)

元函数的参数也可以是另一个元函数,这种元函数被称作高阶元函数。Boost.MPL类库中的transform就属于高阶元函数。

 

Metafunction vs Function(元函数 vs 函数)

 编译期“元函数”运行期“函数”
是否允许返回多值
是否允许不返回值
是否存在副作用
是否允许零参数
能否作为类成员
是否存在高阶函数

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值