Should lambdas capture parameters packs? Due to parts 5.1.2
(expr.prim.lambda) and 14.6.3 (temp.variadic) there is no way to make
pack expansion within lambda function definition. These code samples:
template<typename Op, typename ... F>
function<double (double)> DoOperator(Op op, F ... fs)
{
return [=](double x) -> double {return op(fs(x)...);};
}
and
template<typename Op, typename ... F>
function<double (double)> DoOperator(Op op, F ... fs)
{
return [op, fs...](double x) -> double {return op(fs(x)...);};
}
are not allowed by the current working draft. Is there any significant
reason to to disallow such expansion or this is just an issue?
Second question. Is pack expansions contexts list in clause 4 of
14.6.3 exhaustive? If this list is exhaustive why it doesn't contain
function call context which is demonstrated in the example for this
clause?
--
Best Regards,
Sergey mailto:flex_...@artberg.ru
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
> Hello.
>
> [snipped]
> Second question. Is pack expansions contexts list in clause 4 of
> 14.6.3 exhaustive? If this list is exhaustive why it doesn't contain
> function call context which is demonstrated in the example for this
> clause?
>
The list seems to be exhaustive. In the function call context "f(&rest...)",
the pack expansion occurs in an initializer-list.
Personally I would like the permitted expansion contexts to be
extended to e.g. do/while loop conditions (joined by &&) and arbitrary
statements (joined by ;). It would make using the packs a lot more
natural.
Wouldn't that make them parametric, and thus polymorphic?
The paper explicitly says it only supports monomorphic lambdas.
According to 5.2.2/1, a function call has the form
postfix-expression ( expression-list opt )
expression-list is defined in 5.2/1 as follows:
expression-list:
initializer-list
See 14.6.3/4:
Pack expansions can occur in the following contexts:
� In an initializer-list (8.5); the pattern is an initializer-clause.
[...]
> Personally I would like the permitted expansion contexts to be
> extended to e.g. do/while loop conditions (joined by &&) and arbitrary
> statements (joined by ;). It would make using the packs a lot more
> natural.
Of course, it would be great. But it is able to reach almost the same
functionality within current VT specification. Just combine 'ignore'
function with 'assignment-expression':
template<typename ... T>
void ignore(T ...) {;}
template<typename ... T>
bool IsPositive(T ... nums)
{
bool ret_val = true;
ignore(ret_val = ret_val && nums >= 0 ...);
}
Unfortunately, such functions can not be constexpr...
Nikolay, thanks. I see.
Ah yes, so I see. I hadn't looked through the grammar fully and
assumed an initializer-list could only be used for initializers,
rather than arbitrary function calls.
More problematic, IMO, is that this doesn't appear to work for void-
returning functions, presumably because it cannot construct "void
ignore(void, void, void, void)" (etc.).
>
> More problematic, IMO, is that this doesn't appear to work for void-
> returning functions, presumably because it cannot construct "void
> ignore(void, void, void, void)" (etc.).
I agree with you. But there is workaround present. Here it is:
template<typename ... T>
void ignore(T ... )
{
;
}
template<typename T1, typename ... A>
int void_wrapper(T1 fn, A ... args)
{
fn(args ...);
return 0;
}
void f(int& x)
{
x += 1;
std::cout << x << " ";
}
template<typename ... T>
int do_something(T ... args)
{
ignore(void_wrapper(f, args)...);
return 0;