Boost logo

Boost :

Subject: [boost] [MPL] More lazy evaluation, for ease of use?
From: jcarey_at_[hidden]
Date: 2010-07-30 18:48:02

According to Boost MPL documentation, "Every Integral Constant is also a nullary Metafunction, returning itself."

Put another way: redundant evaluation of an Integral Constant is harmless.

This handy guarantee encourages Metafunctions to evaluate their integral arguments upon demand. As others have pointed out before, such lazy evaluation reduces "typename ...::type" syntactic clutter, makes it easier to avoid instantiating a template with parameters it does not support, and tends to increase compilation speed.

However, other Boost MPL concepts do not impose this self-return requirement, and many Boost MPL standard data types do not provide such a guarantee. In particular, I think it would be helpful if all Sequences, Iterators, and Lambda Expressions were also nullary Metafunctions returning themselves. (In particular, it would be nice if generic containers designed for lazy data could accommodate Lambda Expressions.)

Furthermore, it would be helpful if more standard Metafunctions evaluated their arguments. In particular, if boost::mpl::eval_if were to evaluate its condition argument, then nested ifs would be much easier to write, because nested conditions would not have to be legal for all template parameters.

Perhaps the reason for not evaluating certain arguments is backward compatibility? Personally, I think the convenience of widespread lazy evaluation would outweigh the costs of a transition to new Metafunctions and concepts.

In particular, uniform lazy evaluation would reduce the burden on beginners to figure out which arguments must be evaluated, and which must *not* be evaluated. Instead, beginners could learn the simple rule to leave arguments unevaluated unless there is some good, documented reason to do otherwise.

One special note: It is useful for MPL Metafunctions to be able to reason about arbitrary C++ types, even if those types do not happen to be nullary Metafunctions. For example, a canonical use of MPL is to compute the type returned by a function template. To that end, we could wrap arbitrary types just as we wrap integral values in Integral Constant types, and then unwrap them only at need. For example, we could define:

  template< typename X > struct box {
      typedef box type;
      typedef X content;

  template< typename B > struct open
  : B::type::content {};

and then compute with "box" instances instead of raw types, and apply "open" only when a raw type is actually required.

What do you all think?

Boost list run by bdawes at, gregod at, cpdaniel at, john at