I can create restrict(amp) function as follows:
auto f = [](int& item) restrict(amp) {item += 1;};
And I can use this function in other restrict(amp) functions, for example:
concurrency::parallel_for_each(av.extent,
[=](concurrency::index<1> idx) restrict(amp)
{
f(av[idx]);
}
);
What type of substituted instead "auto" after compilation? I tried to use the "std::function":
std::function<void (int&) restrict(amp)> f
= [](int& item) restrict(amp) {item += 1;};
but received a compile error.
Thank you for your attention!
The result of a lambda expression is a closure object, and the type of the closure object is unknowable. You can only use auto to declare a variable of its exact type.
However, you can convert a closure object into a suitable instance of an std::function, and if the lambda is non-capturing, you can even convert it to a function pointer. However, this conversion may come at a (significant) cost, so you should prefer using auto as much as possible to handle the actual closure type.
The same goes for bind expressions.
The relevant standard section is 5.1.2(3):
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate.
That said, I'm not sure how the special AMP extensions behave in this context, and it's conceivable that AMP-restricted lambdas are not convertible to anything else. I'll try and look this up in the AMP specification.
Update: Sections 2.2.3 and 2.3 of the AMP Specification seem to apply to this question.
Related
I'm starting out with C++ programming, and am curious why this is legal:
auto myFun = [n=0]() mutable {return n++;};
I would have thought this wouldn't work, as C++ is a strong typed language, but it seems that the compiler infers the integer type?
Lambdas, were introduced with C++11. There were no default initializer values in C++11:
auto myFun = [n]() { /* body */ };
That's all you had in C++11. Whatever the type of n was, that's what you captured, type and value.
Default initialization values were introduced with C++14. I suppose that it would've been possible to change the syntax so that the initialized captured variables used a complete, full-fledged declaration, something like:
auto myFun = [int n=0]() mutable {return n++;};
That might've been possible, but this wasn't really necessary. Even though C++14's default capture values do not explicitly state their types, their types are inferred from their initialization expressions just as strongly as if they were explicitly declared. And the resulting change in syntax is minimal. With:
auto myFun = [n=0]() mutable {return n++;};
the type of n is int, just as "strong" as if it were explicitly declared. It is not a char, and it is not a short. It is an int. End of story.
Also, keep in mind that with:
template<typename Arg> void function(Arg arg)
when this is invoked the type of Arg gets deduced, and it becomes a bone-fide, strong type, too. So this is really no different than template parameters: in the end when instantiated their types are still as strong as they are in the rest of C++.
From the reference on lambda captures:
A capture with an initializer acts as if it declares and explicitly captures a variable declared with type auto, ...
This means the [n = 0] is basically treated as if it's
auto n = 0;
The placeholder type is deduced by the compiler as int, and the same type inference happens in the lambda capture.
This convenient syntax of not needing to say auto in the initializer of a lambda capture is just that, a convenience. This syntax doesn't result in any changes to the type safety imposed by the language.
Following code fails with this error
E0413 no suitable conversion function from "lambda []float (int i)->float" to "float (*)(int i)" exists
int test;
float (*f)(int i) = [&](int i) -> float {return test; };
How do I fix this? I need the Capture clause.
You can only do the above with capture-less lambdas.
See [expr.prim.lambda.closure] (sec 7)
The closure type for a non-generic lambda-expression with no
lambda-capture whose constraints (if any) are satisfied has a
conversion function to pointer to function with C++ language linkage
having the same parameter and return types as the closure type's
function call operator.
Since lambdas are not just ordinary functions and capturing it need to preserve a state,
you can not find any simple or conventional solution to make them assign to function pointers.
To fix, you can use std::function which will do it by type erasure:
#include <functional> // std::function
int test;
std::function<float(int)> f = [&](int i) -> float {return static_cast<float>(test); };
A lambda (with captures) is not the same as a function pointer, and cannot be converted to one.
A capture-less lambda can be converted to a function pointer.
See CPPReference, specifically the bit that begins:
A generic captureless lambda has a user-defined conversion function template with the same invented template parameter list as the function-call operator template.
I have read the item31 of "Effective Modern C++" and web page of http://en.cppreference.com/w/cpp/language/lambda and wonder if I can define a lambda by its definite type instead of the wrapped type of std::function or keyword of auto and how can I accomplish that.
for instance, for the type int:
auto x_1 = 5; // type deduction
int x_2 = 5; // defined by definite type
// both x_1, x_2 are int variables of value 5
now, when the problem comes to the lambda:
auto f_1_0 = []()->int{return 5;};
std::function<int(void)> f_1_1 = []()->int{return 5;};
SomeType f_2 = []()->int{return 5;}; // what's the SomeType here?
Each lambda expression has its own unique type.
Here the expressions f_1 and f2 have different types.
auto f_1 = []()->int {return 5; };
auto f_2 = []()->int {return 5; };
Assigning f_2 = f_1 is illegal.
The standard says the types are "unnamed." In practice, the compiler probably makes up a new, hiiden typename for each lambda. Visual C++17 gave them the following names.
classmain::<lambda_7e9d7fb093569d78a8c871761cbb39d7>
classmain::<lambda_8f061a3967cd210147d6a4978ab6e125>
Not very useful information.
The standard says that the type of the lambda is unnamed so the implementation creates a implementation defined name it uses similar to the other unnamed classes, structs enumc etc.
ISO C++: 5.1.2 Lambda expressions [expr.prim.lambda]
3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below.
The standard also says that the lambda 'behaves like a function' so you it could be used with the std::function template:
[Note: A closure object behaves like a function object (20.9).—end note]
And if you really want to have names for your can use the old-fashioned functors and do all the work the compiler do for you with the lambdas.
in some cases you can use function pointers (using mvcpp, 0x17):
auto usingAuto = []() {
cout << "autoMagick" << endl;
};
void(*pureCpp)() = []() {
cout << "pureCpp" << endl;
};
//pureCpp = usingAuto; //you can even assing function pointers from lambdas
//usingAuto = pureCpp; //error
pureCpp();
usingAuto();
Before you throw a rotten tomato
I know the practical application of lambda decomposition is currently limited
as one wouldn't be able to find substitution-failure-friendly way to check
the number of lambda captures hidden in decomposed variables. This is just a theoretical question as I failed to find any standard part covering the capture member variable access modifiers.
Example
int main() {
int a;
auto [x] = [a]{};
static_cast<void>(a);
static_cast<void>(x);
return 0;
}
Standard reference
The standard section about lambda capture is quite long so I might have missed the relevant fragment. What I noticed is that there is an emphasis on that the non-static members which corresponds to the captures are/have to be unnamed.
I'd say this is unspecified by the Standard, but certainly intended to not work. What we know about lambda structure is that, from [expr.prim.lambda.closure]:
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type
and
The closure type is not an aggregate type
and, from [expr.prim.lambda.capture]:
For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified.
and:
It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference. If declared, such non-static data members shall be of literal type.
The intent of having unnamed members is to avoid having them being accessed outside of the lambda's body. The consequence of these members additionally being in unspecified order means as soon as you have more than one capture by copy, you wouldn't even be able to know what your structured binding did.
int a=1, b=2;
auto [x, y] = [a, b]{}; // x==1 or x==2??
The consequence of captures by reference not necessarily naming members means that you wouldn't even know how many identifiers to list in your structured binding declaration.
Since the access of the non-static data members is unspecified, it's possible to have a conforming implementation make them all public, which would satisfy case 3 of structured bindings. But that very much goes against the intent of both the way lambdas are structured and how structured bindings are supposed to work, so I'd be surprised if any implementation knowingly did this. gcc, for instance, explicitly patched to disallow it.
Why lambda expression's capture list cannot be decomposed using structured bindings
It actually can. The following
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
int main()
{
auto f = [x = 1, y = 2]() { return x + y; };
// auto [a, b] = f; // error: cannot decompose lambda closure type 'main()::<lambda()>'
overload o { f, };
auto [a, b] = o;
return b; // returns 2
}
works in GCC trunk https://godbolt.org/z/15c90z.
Here's a lamba wrapper expression defined:
function <int(double)> f =
[](double x) -> int{ return static_cast <int> (x*x); };
It is used like this:
f(someintvalue);
What is the difference between normal functions and wrapped lambdas?
question is - what is the difference between normal function and wrapped lambda?
Normal function is a normal function and what you call "wrapped lambda" is actually a function object.
By the way, why use std::function? You could simply write this:
auto f = [](double x) { return static_cast <int> (x*x); };
//call
int result = f(100.0);
Also, I omitted the return type, as it is implicitly known to the compiler from the return expression. No need to write -> int in the lambda expression.
Lambdas can capture surrounding scope ([=] or [&]) resulting in anonymous structs that contain a member function.
Certain tasks, like accessing lambda (types) across Translation Units, or taking standard pointer-to-memberfunction addresses from lambdas may prove hard/useless because the actual type of the automatically generated 'anonymous' type cannot be known (and is in fact implementation defined).
std::function<> was designed to alleviate exactly that problem: being able to bind a function pointer (semantically) to a lambda (or indeed, whatever callable object)
1: in fact the type can have external linkage, but you cannot portably refer to that from another translation unit because the actual type is implementation defined (and need not even be expressible in C++ code; within the original TU you'd be able to use decltype to get the magic type. Thanks, Luc for the good precisions about this)