Effective modern C + + translator (5)-Clause 4

Source: Internet
Author: User
Tags types of functions

Article 4: Learn how to observe the inferred types

Those who want to know the type of compiler derivation are usually divided into two types, the first being a pragmatist, their motivation usually comes from software-generated problems (for example, they are still debugging), they use the compiler to find, and believe this can help them find the source of the problem (they ' re looking For insights to compilation that can help them identify the source of the problem.). The other is that they explore the derivation rules described in clause 1-3 and confirm the results of their predictions from a large number of deduction scenarios (for this code, I think the deduced type will be ...), but sometimes they just want to simply answer if so, what would be the problem? They may wonder if I use a universal reference (see clause 26) Instead of a constant parameter of an lvalue (for example, in a function's argument list with t&& instead of the const t&) template type deduction will the result change?

Regardless of which category you belong to (both of which are reasonable), the tool you are using depends on what phase of the software development you want to know about the compiler's deduced results, and we will tell you 3 possible ways to get the inferred type when editing the code, the type to derive at compile time, and the type of deduction at run time.

IDE Editor

The code editor in the IDE typically displays their type when you hover over the program entity, such as variables, parameters, functions, and so on, entities. For example, in the following code

Const int  the ;   == &theAnswer;

The IDE editor is likely to show that the type of x is int,y type is const int*.

For this job, your code cannot be overly complex, because it is the compiler inside the IDE that provides this information, and if the compiler does not fully understand and parse your code and produces the result of a type deduction, it cannot tell you the result of the type deduction.

Compiler diagnostics

An effective way to know the result of a compiler's derivation of a type is to have it generate a compile-time error, because the error report will certainly refer to the type that caused the error.

If we want to know the type of x and y in the previous code being pushed out, we first declare but do not define a template, and the code will look like this:

Class/  TD = = "Type displayer"   

Attempting to instantiate this template generates an error message because there is no template definition and you want to see the types of x and Y only need to instantiate the TD with their type

// ///  Decltype use can refer to clause 3     

I use this form of variable name: Variablenametype because: they tend to produce enough useful error messages (I uses variable names of the form variablenametype, because they tend to Y Ield quite informative error messages.) for the above code, one of the compiler's fault diagnostic information is as follows (I highlighted the type derivation result we want)

Error:aggregate ' td<int> xType ' has incomplete type and
cannot be defined
Error:aggregate ' td<const int *>ytype ' has incomplete type
and cannot be defined

Another compiler provides the same information, but the format differs

Error: ' XType ' uses undefined class ' td<int> '
Error: ' YType ' uses undefined class ' Td<const int *> '

In a different format, all the compilers I have tested provide error diagnostic information that includes the type of information.

Run-time output

Using the printf method (not that I recommend you to use printf) the display type information cannot be used at run time, but it requires full control over the output format, and the difficulty is how to make the type of the variable behave reasonably in the form of text, and you may feel "no problem" typeID and std:: Type_info will solve this problem, you think we can write down the following code to know the types of x and Y:

' \ n ' //  '\ n'/  type

This method relies on the fact that the return type is std::type_info when typeID acts on an object, and Type_info has a member function called name, which provides a C-style string (such as a const char*) to represent this type of name

Std::type_info's name does not guarantee that what is returned must be clear, but will help as much as possible, with different compilers offering different degrees, for example: the GNU and clang compilers represent the type of x as "I" and the type of y as "PKI". Once you understand I means that int,pk means pointer to konst Const (two compilers provide a C + + Filt tool to decode these restructured names), understanding the compiler's output will become easier, Microsoft's The translator provides a clearer output, the type of x is the int,y type is int const*.

Because the results for the X and y display are correct, you might think that the problem has been solved, but let's not take it too lightly and look at the more complex example below:

  void F (const////const//   if (!  Vw.empty ()) {f (&vw[0//}

This code is more representative when you want to know what type the compiler deduced, because it involves a user-defined type widget, an STD container std::vector, an auto variable, for example, you might want to know the type of the template parameter T, and the type of the function parameter F.

Using typeid looks like a very straightforward approach (loosing typeid on the problem is straightforward.), just add some code to the type you want to know in F

 template<typename t> void  F (const  t& param) { using   std::cout; cout  <<  " t =  "  << typeid (T). Name () <<  " \n  " ; //  shows the type of T  cout <<  " param =  "  << typeid (param). Name () << "  \n   "; //  shows the type of the parameter param } 

The results of the GNU and Clang implementation are as follows:

T = Pk6widget
param = Pk6widget

We already know that PK means pointer to const, and 6 represents how many letters (widgets) are in the name of the class, so the two compilers tell us that the types of T and Param are both const widget*

The compiler for Morcrosoft provides the following results

T = Class Widget const *
param = Class Widget const *

These three compilers all provide the same information, which may imply that the results should be accurate, but let's look a little more nuanced, in template F, the type of param is declared as constt&, so is it not surprising that Param and T are the same type? If the type of T is int,param the type should be const int& look, it's not the same.

Sadly, the results of std::type_info::name are not to be relied upon, and in this case, the results of the three compilers are incorrect for the Param, and they must be wrong, because the standard (specification) rule is std::type_ The type of info::name processing is treated according to the value passed to the template, as explained in clause 1, which means that if the type itself is a reference, the reference part is ignored, and if the reference is removed and there is a const, the constants are ignored, which is why the const The type of widget* const & is shown as const widget*, first the reference part of the type is ignored, and then the constants of the result are ignored.

Equally sad is that the type information provided by the IDE is also unreliable, or not so practical, for this example, the compiler I know shows the type of T as (this is not what I invented):

Const
Std::_simple_types<std::_wrap_alloc<std::_vec_base_types<widget,
Std::allocator<widget> >::_alloc>::value_type>::value_type *

Display the type of param as:

Const Std::_simple_types<...>::value_type *const &

This show is not as scary as T, in the middle of ... Just means the IDE tells you that I'm going to show the type of T with ... instead of.

Template<typename t>
void f (const t& param)
{
Td<t> Ttype; Elicit errors containing
Td<decltype (param) > Paramtype; T ' s and param ' s types
...
}

My understanding is that most of what is shown here is caused by a TypeDef, and once you get the potential type information through a typedef, you get what you're looking for, but you need to do some work to eliminate some of the types that the IDE initially shows, and, fortunately, Your IDE editor will handle this code better.

(My understanding is the most of the what's displayed here are typedef cruft and that
Once you push through the typedefs to get to the underlying type information,
You get the "looking for," but have to do the work pretty much eliminates
Any utility the display of the types in the IDE originally promised. With any luck,
Your IDE editor does a better job on the code like this.)

In my experience, using the compiler's error diagnostic information to know the type of the variable being pushed out is a relatively reliable method, using the revised function template F to instantiate just the declared template TD, the revised F looks like this

void F (const t& param) {TD////}

Gnu,clang and Microsoft compilers provide error messages with the correct type of T and Param, with different formats displayed, such as in the gun (the format is slightly modified)

Error: ' Td<const Widget *> ttype ' has incomplete type
Error: ' td<const Widget * Const &> Paramtype ' has incomplete
Type

Except typeID.

If you want to get a more correct derivation type at run time, we already know that typeid is not a reliable method, a feasible way is to implement a set of mechanisms to complete the mapping from a type to its representation, conceptually it is not difficult, you only need to use the type Trait and template metaprogramming methods to split a full type (using type trait such as Std::is_const,std::is_ponter,std::is_lvalue_reference), You also need to complete the string representation of each part of the type yourself (although you still need typeid and std::type_info::name to produce a string representation of the user-defined format)

If you often need to use this method and think that the effort spent on debugging, documentation, maintenance is worthwhile, then this is a reasonable way (if you're using such a facility often enough to justify the effort needed t o Write, debug,document, and maintain it, that's a reasonable approach), but if you prefer those that are not very strong but can easily be implemented and provide better results than typeid, You need to notice that many compilers provide language extensions to produce a string representation of a function signature, including the types of functions, templates, and template parameters instantiated from the template.

For example, both GNU and Clang support _pretty_function_,microsoft support for _funcsig_, they represent a variable (in GNU and clang) or a macro (in Microsoft), if we implement template F so

Template<typename t>voidFConstt&param) {#ifDefined (__gnuc__)//for GNU andStd::cout<< __pretty_function__ <<'\ n';//Clang#elifDefined (_msc_ver)Std::cout<< __funcsig__ <<'\ n';//for Microsoft#endif ...}

Call F like before

 const//if (!   Vw.empty ()) {f (&vw[0//}

In GNU we have the following results

void f (const t&) [With T = Const widget*]

Tell us that the type of T is deduced as a const widget* (as with the result we get with typeid, but there is no previous PK encoding and 6 in front of the class name), and it also tells us that the F parameter type is const T& if we extend T in this format, The type we get F is the const Widget * const&, and the answer to typeID is different, but the type information in the error diagnostic information that is generated by using an undefined template is consistent, so it is correct.

Microsoft's _funcsig_ provides the following output:

void __cdecl F<const classwidget*> (const class Widget *const &)

The type in the angle brackets is the type of T being deduced, for the const widget*, the same as the result we get with typeid, the type in parentheses is the type of the function parameter, is the const widget* Const&, and unlike the results we get with typeid,

But it is also consistent with the type information we get at compile time using TD.

Clang's _pretty_function_, although using the same name as GNU, is not the same format as GNU or Microsoft, it only shows:

void f (const Widget *const &)

It shows the type of the parameter directly, but we need to deduce that the type of T is deduced for the const widget* (or we can use the typeID information to get the type of T)

The IDE editor, compiler error diagnostic information, language extensions such as typeid and _pretty_function_,_funcsig_ just help you figure out what the compiler deduced, but in the end, There is nothing to substitute for the type deduction described in clause 1-3 related guidelines.

Please remember:

    • To know the derivation type, you can use the IDE editor, compiler Error diagnostic information, typeid and _prettu_function_,_funcsig_ language extensions.
    • These results may not be very useful or accurate, so it is still necessary to understand the C + + type derivation rules.

Effective modern C + + translator (5)-Clause 4

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.