September 25th, 2019

How do I create a Windows Runtime method that accepts a lambda?

A customer wanted to create a Windows Runtime method that accepted a lambda. But lambdas aren’t valid Windows Runtime types.

// C++/WinRT IDL
runtimeclass MyClass
{
  template<typename TLambda>
  void ApplyFilter(TLambda&& filter); // Does not compile
}

// C++/CX
public ref class MyClass
{
public:
  template<typename TLambda>
  void ApplyFilter(TLambda&& filter); // Does not compile
};

What can we use instead of lambdas?

The Windows Runtime doesn’t support lambdas, but it supports what you typically use the lambda for, which is providing a callback. The thing that represents a function is a delegate.

You can think of a delegate as the Windows Runtime version of a std::function. It’s an object that can hold a lambda or a static function or an object combined with a member function.

// C++/WinRT IDL
delegate Boolean ThingFilter(Thing thing);

runtimeclass MyClass
{
  void ApplyFilter(ThingFilter filter);
}

// C++/CX
public delegate bool ThingFilter(Thing^ thing);

public ref class MyClass
{
public:
  void ApplyFilter(ThingFilter^ filter);
};

You can use the delegate like a function object.

// C++/WinRT
void MyClass::ApplyFilter(ThingFilter const& filter)
{
  things.erase(std::remove_if(things.begin(), things.end(),
    [&](auto&& thing) { return !filter(thing); }),
    things.end());
}

// C++/CX
void MyClass::ApplyFilter(ThingFilter^ filter)
{
  things.erase(std::remove_if(things.begin(), things.end(),
    [&](Thing^ thing) { return !filter(thing); }),
    things.end());
}

Most language projections let you pass a lambda directly. C++/CX is the outlier here. It requires you to wrap it inside an explicit ThingFilter. The other languages will do the wrapping automatically.

// C++/WinRT
c.ApplyFilter([=](auto&& thing) { return IsOkay(thing); });

// C++/CX
c->ApplyFilter(
    ref new ThingFilter([=](Thing^ thing) { return IsOkay(thing); }));

// C#
c.ApplyFilter(thing => IsOkay(thing));

// JavaScript
c.applyFilter(thing => isOkay(thing));

// Visual Basic
c.ApplyFilter(Function (thing As Thing) IsOkay(thing))

 

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • cheong00

    Much like in C# we could write event handler as lambda, but we used to create event handlers as delegates.

    1) this.Click += (s, arg) =>
    {

    };

    2) this.Click += Form1_Click;

    3) this.Click += new EventHandler(Form1_Click);

    private void Form1_Click(object sender, EventArgs e)
    {

    }