学习C++模板元编程(4)

 
《 C++ Template Metaprogramming》的第四章提到了缓式评估(lazy evaluation)和短路行为(short-circuit behavior)两个概念,我编写了一个测试这两种行为的程序,但无法通过编译,还以为是编译器的问题,后来经过仔细思考,才发现是自己弄错了。
我最初的理解是,缓式评估( lazy evaluation)就是if_<>在看到第一个参数为true时,就不会去碰第三个参数;同样,短路行为(short-circuit behavior)就是or_<>在看到第一个参数为true时,也不会去碰第二个参数。于是,我写了以下测试代码:
#include <iostream>
#include <boost/mpl/or.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_reference.hpp>
 
namespace mpl = boost::mpl;
 
template <typename T>
struct LazyEvaluationTest
: mpl::if_< typename boost::is_reference<T>
, typename mpl::identity<T>, mpl::identity<T&> >::type
{
};
 
template <typename T>
struct ShortCircuitTest
: mpl::or_<boost::is_reference<T>, boost::is_reference<T&> >
{
};
 
int main()
{
typedef LazyEvaluationTest<int&>::type t1;
    std::cout << ShortCircuitTest<int&>::value << std::endl;
    return 0;
}
 
我以为,虽然两个测试用的元函数都是以 int&来实例化的,但是相应的if_<>和or_<>里的第一个参数都是true,所以应该不会触碰到后面关于T&的模板。结果编译器报出了“reference to reference”的错误。
一开始,我还以为是 GCC编译器的问题。后来仔细一想,缓式评估(lazy evaluation)和短路行为(short-circuit behavior)的正确含义并不是象我前面所理解的那样。正确的理解应该是:if_<>在看到第一个参数为true时,也要去检查第三个参数的声明是否有效,但不会去触碰它里面的东西(如::type或::value),同样or_<>在看到第一个参数为true时,也要检查第二个参数的声明,但也不会去触碰嵌套在里面的东西,除非嵌套的东西被显式调用。
还是以《 C++ Template Metaprogramming》一书中的例子为例,如果你这样写:
template <class T>
struct param_type
   : mpl::if_<
          typename boost::is_scalar<T>::type
        , T
        , typename boost::add_reference<T const>::type
      >
{
};
 
那么不管 boost::is_scalar<T>::type是true还是false,编译器都要实例化boost::add_reference<T const>以获得嵌套在其内部的::type。而如果你这样写:
template <class T>
struct param_type
    : mpl::if_<           // forwarding to selected transformation
          typename boost::is_scalar<T>::type
        , mpl::identity<T>
        , boost::add_reference<T const>
      >::type
{
};
 
则无论 boost::is_scalar<T>::type是true还是false,编译器都会检查boost::add_reference<T const>的声明是否合法,但不会实例化它,直至你需要嵌套在其内部的::type。
理解了这些之后,我修改了测试的代码,如下:
#include <iostream>
#include <boost/mpl/or.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_reference.hpp>
 
namespace mpl = boost::mpl;
 
template <typename T>
struct ErrorTest
    : boost::is_reference<T&>
{
};
 
template <typename T>
struct LazyEvaluationTest
    : mpl::if_< typename boost::is_reference<T>
        , mpl::identity<T>, ErrorTest<T> >::type
{
};
 
template <typename T>
struct ShortCircuitTest
    : mpl::or_<boost::is_reference<T>, ErrorTest<T> >
{
};
 
int main()
{
    typedef LazyEvaluationTest<int&>::type t1;
    std::cout << ShortCircuitTest<int&>::value << std::endl;
    return 0;
}
 
修改后的代码中增加了一个 ErrorTest<T>模板,它继承自boost::is_reference<T&>,如果使用引用类型(如int&)来实例化,就会产生“reference to reference”的编译错误。接着,两个测试用的元函数LazyEvaluationTest与ShortCircuitTest分别继承自if_<>和or_<>,并且if_<>和or_<>均带有参数ErrorTest<T>,但由于在使用引用类型(如int&)对LazyEvaluationTest或ShortCircuitTest进行实例化时,if_<>和or_<>的第一参数boost::is_reference<T>将为true,因此编译器只会检查ErrorTest<T>的声明而不会触碰其内部(包括它的基类),所以这次不会再出现编译错误了。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值