February 4th, 2021

Abbreviated Function Templates and Constrained Auto

Sy Brand
C++ Developer Advocate

Declaring function templates in C++ has always been quite verbose. C++20 added a new way of doing so that is more terse and more consistent with lambdas: abbreviated function templates. This short post will show how to use this syntax and how it applies to C++20 concepts.

Abbreviated Function Templates

C++11 introduced lambdas, which look like this:

[captures] (type_1 param_1, type_2 param_2) { body(param_1, param_2); }

You can only call this lambdas with arguments of type_1 and type_2. However we frequently use lambdas in situations where the types would be difficult to spell out in full (especially when using features like ranges). C++14 allowed you to make lambdas which can be called with arguments of any type by using the auto keyword:

[captures] (auto param_1, auto param_2) { body(param_1, param_2); }

Now you can pass any types as the arguments. C++20’s abbreviated function templates allows you to apply this kind of syntax to function templates.

In C++17 you might write a function to give animals head scratches as a function template, so it can be called with any type of animal:

template <class Animal>
void give_head_scratches (Animal const& the_animal);

In C++20 you can simplify this using auto:

void give_head_scratches (auto const& the_animal);

This version is less verbose, requires coming up with fewer names, and is more consistent with C++14 lambdas.

Constrained Auto

There’s a problem with the above function template though: according to the declaration we can pass literally anything to it. We can happily make calls that look like this:

give_head_scratches(42);
give_head_scratches(a_cactus);
give_head_scratches(blog_post);
give_head_scratches(the_platonic_ideal_of_a_chair);

They might compile and do something weird, or they might fail to compile due to the implementation of the template doing something which those types don’t support. Ideally we’d want to both document the interface of this function template with what kind of types it supports and also give the compiler the ability to give detailed errors when the declaration is instantiated with in incompatible type.

C++20 gives us Concepts to help solve this problem. If we have some animal concept which defines what interface a type representing an animal should have then we can use it like so:

template <animal Animal>
void give_head_scratches (Animal const& the_animal);

This is quite verbose and repetitive. Ideally we’d be able to use the concept name directly in the function parameter list like this:

void give_head_scratches (animal const& the_animal);

However, this syntax was rejected from standardization, because you can’t tell whether this is a function template or a regular function without knowing whether animal is a type or a concept.

Fortunately, a version of this syntax was included in C++20 which uses the auto keyword again:

void give_head_scratches (animal auto const& the_animal);

This checks that whatever is substituted for auto satisfies the animal concept. So if we instantiate the template with a kitten then animal<kitten> will be checked. This gives us back our terse syntax while also allowing us to constrain our template declarations.

Try Them Out!

Constrained auto has been supported in MSVC since Visual Studio 2019 version 16.8, and abbreviated function templates have recently been added to version 16.9 Preview 3. We encourage you to download the tools and give the implementations a try! We can be reached via the comments below or via email (visualcpp@microsoft.com). If you find any problems you can use the Report a Problem tool in Visual Studio or head over to the Visual Studio Developer Community. You can also find us on Twitter @VisualC.

Category
C++

Author

Sy Brand
C++ Developer Advocate

Sy Brand is Microsoft’s C++ Developer Advocate. Their background is in compilers and debuggers for embedded accelerators, but they’re also interested in generic library design, metaprogramming, functional-style C++, undefined behaviour, and making our communities more inclusive and welcoming.

8 comments

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

  • Lucio Asnaghi

    That constrained auto keyword used in the declaration is horrible imho, it's just an already abused keyword sticked somewhere it shouldn't be nor where it does explain or complete a meaning. Sure it's concise, but `animal auto` really? What's an auto
    something? It can be really confusing to read, a reader could just miss it as that auto could be lost in between const keywords, not really what i would define a clear readable syntax...

    Read more
    • Kalle Niemitalo

      C++20 allows animal decltype(auto) a as well. I think it’s good that auto and decltype(auto) have the same meanings here as in unconstrained templates.

  • Jason Beach

    How does one make an Animal concept though?

    • Me Gusta · Edited

      Use the regular concept syntax.

      <code>

      So as a more complete example:

      <code>

      If you try to use a type that doesn't have the make_sound member, then this will fail to compile.
      Obviously, this isn't the only concept of an animal, it is just an example.

      Read more
      • Willem Pieters

        ah i was looking for it too, thanks!!

        😁
  • Russel Kluting

    Know what

  • MrModez Pineapple · Edited

    Concepts and modules are gonna change the language and the way we use it forever! I’m so excited for a full C++20 support from the major compilers 😀

  • Pol Marcet Sardà

    Thank you for the heads up, Sy! Missed that part of the paper 🙂