////////////////////
///// Implementation
#define AUTO_FUNCTION( ... )\
auto __VA_ARGS__ -> AUTO_FUNCTION_IMPL
#define AUTO_FUNCTION_IMPL( ... )\
decltype( [&]{ __VA_ARGS__ }() ) { __VA_ARGS__ }
///// Usage
template< class L, class R >
AUTO_FUNCTION( add( L left, R right ) )
(
return left + right;
)
////////////////////
This is just one example but it seems to me that there are likely
other use-cases as well. I don't immediately see why there is this
limitation on lambdas, though given that such usage is explicitly
mentioned, I'd imagine that there is a rationale.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
There would indeed exist a huge number of use-cases for allowing lambda
expressions, it would probably extremely extend possible sfinae cases
(to include complete code "sand-boxes"). The reason why they became
excluded was due to exactly this extreme extension of sfinae cases (you
were opening a Pandora box for the compiler) and the fact that it can
lead to problems on other examples as yours, e.g.
template<typename T, typename U>
void g(T, U, decltype([](T x, T y) { return x + y; }) func);
is useless, because every lambda expression generates a unique type, so
something like
g(1, 2, [](int x, int y) { return x + y; });
doesn't actually work, because the type of the lambda used in the
parameter is different from the type of the lambda in the call to g.
Finally it did also cause name-mangling issues. E.g. when you have
template<typename T>
void f(T, A<sizeof([](T x, T y) { return x + y; })> * = 0);
in one translation unit but
template<typename T>
void f(T, A<sizeof([](T x, T y) { return x - y; })> * = 0);
in another translation unit. Assume now that you instantiate f<int>
from both translation units. These two functions have different
signatures, so they must produce differently-mangled template
instantiations. The only way to keep them separate is to mangle the
*body* of the lambdas. That, in turn, means that compiler writers have
to come up with name mangling rules for every kind of statement in the
language. While technically possible, this was considered as both a
specification and an implementation burden.
HTH & Greetings from Bremen,
Daniel Krügler
In addition to what I wrote in my first reply, it would IMO make much
more sense in regard to your example to extend the language to allow for
auto return type deduction for function definitions such that
template< class L, class R>
auto add( L left, R right )
(
return left + right;
)
would just become well-formed. The not-so-nice part of this suggestion
is that decltype and return type deduction in lambda-expressions have
slightly different semantics.
HTH & Greetings from Bremen,
Daniel Krügler
Read on (paragraph 3):
"The type of the lambda-expression (which is also the type of the
closure object) is a unique, unnamed nonunion class type..."
So, at least the use of decltype makes little sense because two lambda
expression never have the same type.
It seems, what you're trying to do is to remove the redundancy we're
currently stuck with (unfortunately) with respect to the '->'-syntax
for the late return type. But I don't see how this has anything to do
with lambda expressions. Try this:
#define AUTOFUN_IMPL(...) -> decltype(__VAR_ARGS__) \
{return __VAR_ARGS__;}
template<class L, class R>
auto add(L left, R right)
AUTOFUN_IMPL(left+right)
In my opinion, C++0x should treat "auto functions" with a lacking "->
type" the same way it handles lambda expressions already. The function
could be implicitly inline and needs to have a single statement of the
form "return expression;" as its body. However, as far as I know, the
"-> type" part is not optional for non-lambdas. :-(
In other cases you might be able to use 'auto' like this:
auto fun = [](int x, int y){return x>y;}
std::set<int,decltype(fun)> myset (fun);
Here, decltype is not applied on a lambda expression but an object of
a corresponding closure type which is fine.
Cheers,
SG
Ha, well, I actually was hoping it would work with SFINAE there too,
but I guess I should have figured that was one of the very reasons why
it's not allowed. Thanks for the very detailed reply.
That is actually much more similar to how I originally implemented the
macro, though I was hoping that a clever use of lambdas could get
exactly what lambdas provide, though as I've learned, it's disallowed.
Anyway, as was said, I think function templates should really be
allowed to have automatically deduced return types much like
lambdas :/ It's sort of an embarrassment that we even have to make a
macro to get rid of this redundancy particularly when another feature
in the language already does pretty much exactly what is wanted.
> In other cases you might be able to use 'auto' like this:
>
> auto fun = [](int x, int y){return x>y;}
Right, but lambdas can't be templates and can't be overloaded, so uses
are very limited when trying to use lambdas simply for an
automatically deduced return type.
> In addition to what I wrote in my first reply, it would IMO make much
> more sense in regard to your example to extend the language to allow for
> auto return type deduction for function definitions such that
>
> template< class L, class R>
> auto add( L left, R right )
> (
> return left + right;
> )
>
> would just become well-formed.
Hear, hear!
It's just an embarrassment to have to duplicate small pieces of code.
I get a lough out of my lisp friends every time I mention the new "auto deduced" function syntax. It actually supposed to help reduce boilerplate code. Most of the time the body of these functions is a small (single-line) expression (just like in Daniel's example) that should be trivial to deduce the type from. And it's a shame to have to duplicate it verbatim. Moreover, it seems to work just fine for c++0x lambdas, but not for the auto return.
I'm sure that there have been plenty of discussions on this (right?), but could we please have another one? I know it's probably too late for the inclusion into the standard, but generating a healthy discussion is always helpful. I'm sure that there's a growing body of C++ engineers who are deeply dissatisfied with the current state of auto deduced functions.
So, what was the reason to ALWAYS require ->decltype, and is there any chance to change that in the standard?
<snip>
Thanks,
Andy.
While from what I understand it's likely too late to add automatically
deduced return types to regular functions and function templates to
the standard, would it be feasible to allow lambdas in unevaluated
contexts with it also being specified in the standard that
substitution failure in the body of a lambda function would cause
error rather than trigger SFINAE? This at least allows for some of the
use-cases of lambdas in unevaluated concepts (for instance, the macro
I presented would work, though it would directly produce an error
during substitution if left + right isn't valid for the respective
types). Would this be an acceptable trade-off and simple enough to
squeeze into the standard?
My personal opinion is, that auto return type deduction of function
definitions will get much easier supported than allowing for lambda
expressions in unevaluated contexts (even with the restrictions you
mention). I don't expect that either of them will be added for C++0x,
but the former has IMO a much lesser barrier. AFAIK there do not exist
*any* technical nor fundamental wording problems that speak against the
first alternative, while there speak both technical *and* wording
problems against the second one. I think the former was just not added
because it was considered to have too much feature character when it was
first suggested and/or there was too little time in the end to provide
them. Further, there is a subtle difference compared to decltype
deduction, which requires some thinking about the "right way".
Lambda auto-deduced return types perform lvalue-to-rvalue conversion,
array-to-pointer conversion, and function-to-pointer conversion on the
actual type of the return expression, but decltype does not.
HTH & Greetings from Bremen,
Daniel Kr�gler