Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-10-09 10:44:28

"Joel de Guzman" <joel_at_[hidden]> writes:

> David B. Held <dheld_at_[hidden]> wrote:

> struct square
> {
> template <class X>
> struct sig { typedef X type; }
> template <class X>
> X operator()(X x) { return x * x; }
> };
>>> [...]
>>> b. It should be called apply, because that just makes it
>>> cheaper and easier to use: instead of
>>> [...]
>> But my understanding is that apply<> is the compile-time way
>> to spell "operator()" for function objects.

Sort of.

>> If sig<> is really the definition of R for "R operator()", without
>> being the result of operator(), should it really be spelled
>> "apply<>"? It seems to me that there is a confusion between
>> runtime and compile time here. The fact that apply<> works
>> syntactically adds to the confusion.

*I'm* not confused. I have no problem with the idea of having a

  a. whose _instances_ can be used as a function which squares numbers

  b. which is itself a metafunction class that computes the instance's
     return type based on the arguments passed

The fact that the metafunction role is the identity doesn't bother me
at all.

>> In Joel's example above, square could be a metafunction
>> object as well as a function object.

Uh, what is a "metafunction object"?

square can't be an object. Maybe you meant square() (an instance of

>> But what kind of metafunction is it? It's the identity
>> metafunction. Clearly, this is different from it's name and
>> run-time purpose. That's because sig<> does not reflect it's
>> intent, only its return value to support lazy evaluation.

Intent is in the eye of the beholder. I have no problem with dual
roles, "as a metafunction class, its intent is X. As the type of a
function object, its intent is Y"... as long as X is related to Y.

>> So in this case, I think calling the return type metafunction
>> "apply<>" is confusing, even though it makes it convenient
>> to use with MPL::lambda.

Actually, it makes it convenient to use _without_ lambda, and in
particular without the macro hackery workarounds that would be
required if it were called sig.

>> I think I agree with Joel that it should be called result<>. Even
>> though it *could* be used with lambda, how would you do so? The
>> result of apply<> is not square, as one would hope, but X. What
>> are you going to do with the return type by itself?

Say you're building a tuple transform iterator. You have a functoid
and an mpl::list of the underlying sequence value_types, and you want
to compute the return types of the dereference operator.

    typedef mpl::transform<
      , functoid
>::type outer_value_types;

The fact that it took me all of 5 seconds to come up with this
example tells me there are lots of others ;-)

>> There definitely needs to be a convention. And maybe
>> ReturnTypeMetafunction needs to be a formal concept
>> that encapsulates that convention and specifies a name.
>> But I don't think the name should be "apply<>".

Well, the alternative wouldn't be so terrible on a conforming

    typedef mpl::transform<
      , functoid::result<_1>
>::type outer_value_types;

The drawbacks are that it's probably more costly in compile-time
resources, and it supporting the lambda notation on broken compilers
requires an ugly macro hack inside of functoid::result. In fact, I'm
not even sure you can do it there with a macro. You may need to use

  template <class T>
  struct functoid_result
     typedef whatever type;

  struct functoid
     template <class T>
     struct result : functoid_result {};

And, AFAIK, there are lots of cases where forwarded lambda support
doesn't work. So, all I'm saying is that it gets sticky in this
territory. Everyone can make his own judgement about whether the name
"apply" is evil enough to make up for the other complications.

Dave Abrahams
Boost Consulting

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