Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization and references

In Functional programming in C++, chapter 11 deals with some basic template meta programming.

In this context, the author shows this implementation of remove_reference/remove_reference_t, which are essentially the same as those described on cppreference.

template<typename T> struct remove_reference      { using type = T; };
template<typename T> struct remove_reference<T&>  { using type = T; };
template<typename T> struct remove_reference<T&&> { using type = T; };
template<typename T> using remove_reference_t = typename remove_reference<T>::type;

With reference to the code above, the author comments that when "calling" remove_reference_t<int>, only the general (or primary? What is the correcto word here?) template successfully substitutes T, and the other two fail. This is clear to me, there's no way int can be written as/matched against T& or T&&.

As regards remove_reference_t<int&>, however, the author says that the second specialization cannot match. Well, couldn't it be a match thanks to reference collapsing? I mean, can't T&& match int& if I substitute T for int&, thus getting int&&& == int&?

Similarly, when calling remove_reference_t<int&&>, can't the first specialization's T& match int&& if T is substituted for int&? (Why in the world did I think that & & would collapse to && instead of &?)

What makes the compiler discard one specialization?

like image 235
Enlico Avatar asked Sep 08 '20 21:09

Enlico


People also ask

What is meant by template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What does template <> mean in C++?

What Does Template Mean? A template is a C++ programming feature that permits function and class operations with generic types, which allows functionality with different data types without rewriting entire code blocks for each type.

Which keyword can be used to create a template in C++?

5. Which keyword is used for the template? Explanation: C++ uses template reserved keyword for defining templates.

What is template specialization in C++ with example?

Template Specialization (C++) The result is a template parameterized on the remaining types. A template has only one type, but a specialization is needed for pointer, reference, pointer to member, or function pointer types. The specialization itself is still a template on the type pointed to or referenced.

What is an explicit specialization of a template member?

Members of specializations. An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. These definitions must use braces for default initialization:

Can a class template be partially specialized?

Thank you. Class templates can be partially specialized, and the resulting class is still a template. Partial specialization allows template code to be partially customized for specific types in situations, such as: A template has multiple types and only some of them need to be specialized.

What is an example of partial specialization?

Example: Define partial specialization so one type is int Class templates can be partially specialized, and the resulting class is still a template. Partial specialization allows template code to be partially customized for specific types in situations, such as: A template has multiple types and only some of them need to be specialized.


1 Answers

only the general (or primary? What is the correcto word here?) template

The technical term used by the C++ Standard is "primary class template". It will also be the most general class template, compared to its partial specializations and explicit specializations. So that could also be a reasonable thing to call it, given enough context.

The "reference collapsing rule" is found in [dcl.ref]/6 and applies mainly when determining the meaning of combining a specific type name which aliases a reference type with a & or && token which would normally form a reference to the type name's type. Deducing template arguments for a template parameter of the form T& or T&& is sort of the reverse of that. Although it's helpful to think of template argument deduction as "find the template arguments so that the resulting types match up", the technical details of template argument deduction are much more specific; [temp.deduct] is several pages of rules for exactly how this deduction proceeds, and there are additional relevant rules in other sections. The detail is needed so compilers agree on cases when there could otherwise be more than one "correct" answer, and so that compilers aren't required to deal with some of the more difficult cases.

In particular, when matching a dependent type P with a known type A, by the list of deducible types in [temp.deduct.type]/8, deduction can occur if both P and A have the form T& or if both have the form T&&. When attempting argument deduction for the partial specialization remove_reference<T&&> to determine the definition of remove_reference<int&>, P is T&& and A is int&, so they do not share one of these forms.

The template argument deduction rules do not have a general allowance for deducing arguments from a reverse of the reference collapsing rule. But they do have a limited allowance which is related for certain cases: Per [temp.deduct.call]/3, if T is a template type parameter, but not a parameter for a class template, then the type T&& is a forwarding reference. When comparing types for argument deduction, if P=T&& is a forwarding reference type and A is an lvalue reference type, then the template type parameter T can be deduced as the lvalue reference type A, only if A is the type of an lvalue function argument expression ([temp.deduct.call]/3 again) or sometimes if P and A are being compared because they represent function parameter types within two compared function types ([temp.deduct.type]/10).

Similarly, when ["]calling["] remove_reference_t<int&&>, can't the first specialization's T& match int&& if T is substituted for T&?

In this case, there's no possible way that the partial specialization remove_reference<T&> can match remove_reference<int&&>. Even if the process of template argument deduction allowed finding a potential answer for this case, there is no possible type T such that T& is the same as int&&.

like image 101
aschepler Avatar answered Oct 19 '22 18:10

aschepler