Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In std::exchange, why is the second template parameter defaulted?

The C++14 standard specifies the following declaration for std::exchange:

template <class T, class U = T> T std::exchange(T& obj, U&& new_value); 

I am wondering why U is defaulted to T since U can be found thanks to new_value. In what case, this would lead to a different result than:

template <class T, class U> T std::exchange(T& obj, U&& new_value); 
like image 705
Vincent Avatar asked Jan 19 '16 12:01

Vincent


People also ask

Can template have default parameters?

You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.


1 Answers

The std::exchange was proposed in N3511 without default template argument, and later N3608 with a default template argument. Note that in N3608 the following reasoning was provided:

Giving the second template argument a default value fixes the following two cases:

DefaultConstructible x = ...; if (exchange(x, {})) { ... }  int (*fp)(int); int f(int); double f(double); /*...*/ exchange(fp, &f) /*...*/ 

The first example's usefullness is of course that an untyped temporary {} will be deduced to T. The second example is more involved:

14.8.2 Template argument deduction [temp.deduct]

5 The resulting substituted and adjusted function type is used as the type of the function template for template argument deduction. If a template argument has not been deduced and its corresponding template parameter has a default argument, the template argument is determined by substituting the template arguments determined for preceding template parameters into the default argument. If the substitution results in an invalid type, as described above, type deduction fails.

14.8.2.5 Deducing template arguments from a type [temp.deduct.type]

4 In most cases, the types, templates, and non-type values that are used to compose P participate in template argument deduction. That is, they may be used to determine the value of a template argument, and the value so determined must be consistent with the values determined elsewhere. In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

5 The non-deduced contexts are:

(5.5) — A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:

(5.5.1) — more than one function matches the function parameter type (resulting in an ambiguous deduction)

In the second example, the template parameter U is only used in a non-deduced context because the two overloads f(int) and f(double) both can be matched to U. Hence, argument deduction does not take place, and U becomes the supplied default value of T (int (*)(int) in this case, so f(int) is selected).

In addition, as explained by @VladfromMoscow, having a defaulted parameter allows for shorter code when passing std::exchange<T> (to a standard algorithm e.g.).

like image 191
TemplateRex Avatar answered Oct 14 '22 03:10

TemplateRex