Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to restrict lambda parameter's parameter to only be a reference?

I’m trying to design a simple function like this:

void draw(Callback callback)
{
    Drawing drawing("name");
    callback(drawing);

    std::cout << drawing.name() << std::endl;
}

where drawing should be passed to the callback as a reference, so that the caller can modify it like so:

draw([](auto& drawing) {
    drawing.set_name("another name");
});

Now this works, because I’m explicitly typing the callback parameter as auto& (or Drawing&).
However, when I just type the parameter as auto (or Drawing), the code also compiles but no longer works as expected. The drawing instance is copied rather than passed by reference.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I’d like the code to no longer compile when the lambda parameter is not explicitly typed as a reference.

I’ve tried the following:

  • using Callback = std::function<void(Drawing&)>;: drawing is not modified when not explicitly typing as auto&.
  • template<typename T> concept Callback = std::is_invocable<void, T, Drawing&>;: same as above.
  • using Callback = void (*)(Drawing&);: this actually works, but I loose the ability to use capture.

So how do I go about properly typing Callback so that only Drawing& is a valid parameter to the lambda?

>Solution :

You could constrain draw so that it cannot be called with an rvalue-accepting callback:

template <typename Callback>
  requires (std::invocable<Callback, Drawing&> && !std::invocable<Callback, Drawing&&>)
void draw(Callback callback)
{
    Drawing drawing("name");
    callback(drawing);

    std::cout << drawing.name() << std::endl;
}

If the given callback accepted auto or auto&&, it would not satisfy the constraint:

int main() {
    draw([](auto& drawing) {}); // OK
    draw([](auto drawing) {});  // error: no matching function call ...
}

See live example at Compiler Explorer.

Note that if your goal is that Drawing isn’t accidentally copied, you can more reliably prevent this by explicitly deleting its copy constructor and copy assignment operator.
However, that would obviously apply everywhere, not just within draw.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading