1. Based on Meyers' Efficient and Modern C ++ "- deduction of template type

Good afternoon, dear reader!


This article is the first in a series of abstracts, which I will write in the course of reading Scott Meyers' book Effective and Modern C ++. Each of these articles will correspond to a separate directory in the project specifically instituted on github.com with examples of using the described features and techniques.


Template Type Output


Successful design is when the consumer does not know how the device works, but everything suits him.


The output of a template type is when there is a template function, for example, and its call is made without any such template and angle brackets. At the same time, the compiler guesses which type should be used in a specific function object.


Meyers shares the type - "T" , which is displayed and the view - "ParamType" , which is written by the programmer in the definition of the parameter.


1. Type of parameter - link or pointer


In order to quickly understand the deduction rule, I will reflect it as a template:


input type -> type, parameter -> inferred type [, finite-type parameter ]


Example with a link:


template<typename T> // выведенный тип T
void func(T& param)// тип параметра - T&
int x = 0; // входной тип int func(x);

In the derivation of type T, referencing (*, &) is discarded, because it is already indicated in the definition of the function, as it implies "you transfer anything there, we will assume that this is not a link, because reference is already added at the place of consumption - in our function f "


By the same principle, constancy is discarded if it is specified in the function parameter. Links, pointers constancy, as it were imposed exclusive mask.


Inference scheme


// отбрасывается ссылочностьint —> (T & param) —> int;
constint —> (T & param) —> constint;
constint & —> (T & param)  —> constint// отбрасывается константностьint —> (const T & param) —> int;
constint —> (const T & param) —> int;
constint & —> (const T & param) —> int;
// отбрасывается ссылочность  int * —> (T * param) —> int;
constint —> (T * param) —> constint;
constint * —> (T * param)  —> constint;
// отбрасывается константностьint * —> (const T * param) —> int;
constint —> (const T * param) —> int;
constint * —> (const T * param)  —> int;

2. Type of argument - universal link


Scott mentions that universal links will be considered later, so the rules for the parameters that he divides here into rvalue and lvalue just need to be remembered without much thought.


template<typename T>
voidfunc(const T&& param)

Output rules for lvalue


This, says Scott, is the only case where T is displayed as a link.
In the following examples, the parameter type in the function description is the universal reference lvalue . It can be seen that T is displayed as a link or a constant link, depending
on the input argument, the type of the param parameter itself in this case is also a link.


lvalue int —> (T &&param) —> int &, param - int&
lvalue constint —> (T &&param) —> constint &, param - constint&
lvalue constint & —> (T &&param) —> constint &, param - constint&

The type of the parameter itself is also replaced. I think this is due to the fact that the language can not be considered lvalue-variable, allotsirovannuyu somewhere higher in that you can move further. We will understand later when we get to the universal links.
To check that T is really a type-reference, I wrote T myVar in the body of the template function, which this T both printed and expectedly received the message - link :)


Output rules for rvalue


The “normal” rules of clause 1 apply.


rvalue int —> (T &&param) —> int, param - int&&

It is already clear that universal references are "included" only for rvalue-temporary objects, in other cases, when the argument is not a universal reference, the distinction between rvalue and lvalue is not made


3. Pass by value (as is)


When passed by value, constancy and referencing of the original argument is discarded as unnecessary because they are absolutely new independent objects, why do they need qualifiers of what they are not connected with?


int —> (T param) —> intconstint —> (T param) —> intconstint & —> (T param) —> int// Хитрый пример с отбрасыванием крайней константности указателя, который копируется при передачеconstchar * const —> (T param) —>  constchar *

I suppose that other crazy and illogical combinations will cause compilation errors, almost always, it turns out, the work of the compiler is explicable, it is only necessary to listen to these explanations once.


Also popular now: