Argument deduction constraints

By , last updated June 23, 2019

Argument deduction constraints are similar to implicit conversion constraints, except argument deduction constraints have one or more placeholders in the trailing return type field.

A placeholder is the keyword auto used in a template argument list within a concept requires clause.

Here is an example of an argument deduction constraint:

First we need a template type to use in our experiment. It accepts two template parameters.

template<typename T, typename U> struct Pair{};

Next, we use the true concept and put it to good use. Why will be explained later.

template<typename T>
concept bool C1() { return true; }

Here is the argument deduction concept in all its glory.

template<typename T>
concept bool C2() 
{
    return requires(T t) 
    {
        {*t} -> Pair<C1&, auto>; // auto is the placeholder
    };
}

Most of the concept is just a standard function concept. The interesting part is the line:

{*t} -> Pair<C1&, auto>;

Part by part, the requires expression works like this:

  1. The dereferencing of t, {*t}, must match the trailing return type indicated by ->.
  2. The result of the dereferencing must result into the type Pair<T,U>.
  3. Within Pair,
  4. the type of T must be equivalent to C1&. This means the type of T must be a reference type.
  5. The second parameter U is deferred to later with auto, also known as argument deduction.

This code will pass the argument deduction constraint.

template<C2 T> void arg_deduction(T)
{}

auto *pair = new Pair<int&, double>(); 
arg_deduction(pair); 

As long as the variable is a pointer of Pair<T,U>, and the type T is a reference, all is good.

Professional Software Developer, doing mostly C++. Connect with Kent on Twitter.