restrict(amp) restrictions part 9 of N – lambda expressions capture rules


This post assumes and requires that you have read the introductory post to this series which also includes a table of content. With that out of the way let’s look at restrictions on amp lambda capture rules.

There are some restrictions on what and how context variables can be captured by an amp-restricted lambda expression:

  • The type of a captured variable must satisfy amp type restrictions for class data members;
  • All context variables must be captured by value except for concurrency::array and concurrency::graphics::texture objects, which are only allowed to be captured by reference;

For example,

class B

{

public:

       B(array<int, 1>& a, int n) : m1(a), m2(n) {}

private:

    array<int, 1>& m1;  // legal, concurrency::array& is allowed for data members

    int            m2;

};

 

void foo(array<int,1> &a1, array<int,1> &a2) restrict(amp)

{

    int n;

    int *p = &n;

int &r = n;

B b(m1, n);

    auto f = [&n,  // illegal since only capture-by-value is allowed for n

              p,   // illegal since pointer is not allowed for class data members

              r,   // legal since reference type captured by value becomes value type!

              &a1, // legal since a1 is a concurrency::array object

              a2,  // illegal since array<int,1> object should not be captured by value 

              b,   // legal since b is captured by value

             ]() { };

}

Note that capturing the “this” pointer is also not allowed since it will result in a pointer data member in the generated lambda class. This causes some inconvenience when using lambda expressions inside an amp restricted member function because we cannot refer to the enclosing object’s data members directly in the lambda expression. The workaround is to declare a local reference variable to the data member, and capture that local variable in the lambda expression instead. For example,

class Scale

{

public:

    int Apply(array<int,1> &a, unsigned int start, unsigned int end) restrict(amp)

    {

        int &rScale = scale;

        auto f = [rScale](int n) { return n * rScale; };

        for (unsigned int i = start; i < end; i++)

        {

            a(i) = f(a(i));

        }

    }

private:

    int scale;

};

Comments (2)

  1. Arman says:

    Thanks for providing this invaluable reference. You say that "The type of a captured variable must satisfy amp type restrictions for class data members", but I don't see anywhere in this blog series where you specify type restrictions for class data members specifically. Could you hotlink that quote?

  2. Arman says:

    Sorry I just realised that this simply falls under compound type restrictions that you have already discussed. Never mind me.