Geoffrey Romer
On 10/6/05, David Abrahams
wrote: Geoffrey Romer
writes: On 10/6/05, David Abrahams
wrote: Oh. Maybe mapping into the runtime world will help. If you think of metafunc as a regular function, then "metafunc
::type" is equivalent to a regular function call, and "metafunc " is equivalent to boost::bind(func, args...) These are exact analogies, AFAICT.
OK, that's what I thought, but it seems not to apply to lambda-expressions. If I want to call foo<> on a placeholder
I don't know what you mean, but I'm pretty sure you don't mean what you said. Nobody but the MPL internals want to actually invoke metafunctions on placeholders. Very often that will cause an error, because the placeholder does not meet the expectations of the metafunction for the type that is actually supposed to be passed to it.
Let me put it like this: suppose I have some metaprogramming expression like
typename foo
::type Now suppose I want to apply this operation to a sequence of types, rather than to baz, using transform<>. To do this, I need to convert it to a lambda-expression to pass to transform<>. Intuitively, I would expect this to be done by replacing baz with _1:
typename foo
::type >::type But this doesn't compile for the reasons you explain. You seem to be telling me to eliminate the typename...::type on metafunction calls that contain actual placeholders as arguments (and in practice this seems to work), which leads to:
typename foo
>::type I take it that's correct? If so, suppose now that I have another piece of code:
No, that won't work. There's still a direct invocation there. Take
this as a general rule: you never want to ask for the nested ::type of
a template that has a placeholder in any of its arguments, unless that
template is specifically designed to operate on lambda expressions.
I assume foo is not one of those. To translate the above into a
lambda expression:
foo
typename foo
::type In other words, "apply foo to the nullary metafunction bar<baz>". Now suppose again that I want to turn this into an equivalent lambda-expression. Intuitively, I would again expect to do this by substituting _1 for baz:
typename foo
>::type. However, this is identical to the lambda-expression for my first example, which has different semantics, so one of the two must be wrong. Which is wrong, and how can I fix it?
They're both wrong. The first is wrong for the reasons already
described. The second is wrong for the same reasons, and even after
you strip the ::type, you have other problems:
The MPL lambda expression mechanism will recognize bar<_1>
as something that demands substitution, perform the substitution, then
look for a nested ::type. When it finds that (it will, since bar is a
unary metafunction), that ::type will be passed on to foo.
AFAIK, the only way to get that case to work is to write a new
metafunction that does what you want:
template<class T>
struct foo_of_lazy_bar
{
// a nullary metafunction
typedef bar<T> lazy_bar;
// apply foo to that nullary metafunction
typedef typename foo
Thanks for all your help, by the way. I'm being a bit stubborn about this because I want to make sure I really know what's going on here.
You're welcome. -- Dave Abrahams Boost Consulting www.boost-consulting.com