Good afternoon, dear reader!
This article is the second in a series of abstracts, which I will write in the course of reading Scott Meyers bestseller "Effective and modern c ++". Each of these articles will correspond to a separate directory in the project specifically instituted on github.com with live examples of using what we are reading today.
This article complements the type inference rules from the previous article and deals with specific aspects of the output of a pattern type for arguments that are an array and a function.
Pattern type output for array
The c ++ compiler has such a property that the declared array is always, when passed to a template function with a parameter declared not as a link, always converted to a pointer to the stored type and back, if the parameter is declared as a link, such a conversion is not performed.
Sample Functions:
To begin with, I will give the code of template functions that derive the coveted types, and then the inference process itself:
template<typename T> void paramDeductInfo(T param, const char *initType) { std::cout << initType << " -> (T param) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; }; template<typename T> void refParamDeductInfo(T ¶m, const char *initType) { std::cout << initType << " -> (T ¶m) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; };
Type inference:
cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CHAR"); char charSeq[] = "Hi everyone!"; paramDeductInfo(charSeq, "char []"); refParamDeductInfo(charSeq, "char []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF INT"); int intSeq[] = {1, 2, 3}; paramDeductInfo(intSeq, "int []"); refParamDeductInfo(intSeq, "int []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CLASS A"); class A { } const classASeq[] = {A(), A(), A()}; paramDeductInfo(classASeq, "class A[]"); refParamDeductInfo(classASeq, "class A[]");
The following pseudocode, reflects the output to the console of these instructions:
************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CHAR ************************************************************************************************************************ char [] -> (T param) -> char* char [] -> (T ¶m) -> char [13] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF INT ************************************************************************************************************************ int [] -> (T param) -> int* int [] -> (T ¶m) -> int [3] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CLASS A ************************************************************************************************************************ class A[] -> (T param) -> main::A const* class A[] -> (T ¶m) -> main::A const [3]
Example 1 - compile-time array length analysis
Moreover, the output array type stores information about its size, which can be used in the template function to manipulate the size of the array at compile time or to generate more efficient code.
I used this feature in the printCaption function to limit the length of the header displayed on the command line during compilation. Trifle, but nice.
namespace cli { template<typename T, std::size_t N> constexpr void printCaption(T (&capValue)[N]) { static_assert(N <= 121, "caption length should be less than 120"); std::cout << std::endl << "*******************************************************************************" << std::endl << capValue << std::endl << "*******************************************************************************" << std::endl << std::endl; }; }
Let's check if there will be an error if we introduce a clearly non-compliant header.
cli::printCaption("123456789 123456789 123456789 123456789 123456789 123456789 123456789" "123456789 123456789 123456789 123456789 123456789 !");
And here you, please, well, is it not wonderful?
/...sources/cli.h:12:3: error: static assertion failed: caption length should be less than 120 static_assert(N <= 121, "caption length should be less than 120"); ^~~~~~~~~~~~~
Example 2 - foreach on memory array
I think that such an approach might seem useful if we have an array size in compile-time, why not use it to organize a loop on such an array?
template<typename T, size_t N, typename F> void forEachOnAnArray(T (&inmemArray)[N], F &callback) { for (int i = 0; i < N; ++i) callback(inmemArray[i]); };
Using this function is as follows:
auto printInt = [](int value) { std::cout << " " << value; }; forEachOnAnArray(intSeq, printInt);
In general, using this feature is by no means limited to pulling out the size of an array.
Type inference for function
Speaking of type deduction for the Meyers function is concise. He mentions exactly that they are cast to a pointer in the same way as for arrays, except when the parameter of the template function by which our type of function is to be output is not declared as a reference.
Probably he should have talked about some kind of template wrappers for functions, but I suppose it just goes beyond the scope of the question of an effective and modern c ++.
We, my dear reader, will definitely return to this issue!
Thanks and have a nice day!!