Automatic code generation-the odd tricks of macros

Source: Internet
Author: User

A major function of macros is to automatically generate code for us. If the template can generate various types of code (type replacement) for us, the macro can actually generate new Code (that is, replacing and adding symbols) for us on the symbol ).

 

1. Macros can be defined like functions.

 

2. if a macro requires a parameter, you can skip it. The compiler will warn you (the macro parameter is not enough), but this will cause errors, as described in C ++, compilers (pre-processors) macro syntax check is not enough, so you have to do more checks on your own.

 

3. # directly convert a symbol into a string, for example

# Define string (x) # x <br/> const char * STR = string (test_string ); 

The STR content is "test_string", that is, # Double quotation marks are directly added to the symbol.

 

# A symbol connects two symbols to generate a new symbol (syntax level), for example:

# Define sign (x) int _ # x <br/> int sign (1 ); 

After the macro is expanded, it will become: int int_1;

 

4. Change the parameter macro so that you can define a macro like this:

# Define log (format,...) printf (format, _ va_args _) <br/> log ("% S % d", STR, count ); 

_ Va_args _ is a system preset macro, which is automatically replaced with the parameter list.

 

5. When a macro calls itself,

# Define test (x) (x + test (x) <br/> test (1 ); 

What will happen? To prevent unrestricted recursive expansion, the syntax stipulates that when a macro encounters itself, it stops expansion, that is,

When the test (1) is expanded, another test is found during the expansion process, so the test is treated as a general symbol. Test (1) is finally expanded to: 1 + test (1 ).

 

6. prescan of macro parameters

When a macro parameter is placed into the macro body, this macro parameter is first expanded (with exceptions ). When the expanded macro parameters are placed into the macro, the pre-processor performs a second scan on the new macro and continues to expand. For example:

# Define param (x) x <br/> # define addparam (x) int _ # x <br/> param (addparam (1 )); 

Because addparam (1) is used as the macro parameter of Param, we first expand addparam (1) To int_1, and then put int_1 into Param.

 

The exception is that if you use # Or # For macro parameters in the param macro, the macro parameters are not expanded:

# Define param (x) # x <br/> # define addparam (x) int _ # x <br/> param (addparam (1 ));

// Expand to "addparam (1 )".

 

Using such a rule, you can create an interesting technology: print out a macro after it is expanded, so that you can analyze the code easily:

# Define to_string (x) to_string1 (x) <br/> # define to_string1 (x) # x 

 

To_string first expands all X (if X is also a macro), and then passes it to to_string1 to convert it to a string. Now you can:

Const char * STR = to_string (param (addparam (1); check the expanded Param.

 

7. A very important addition: If a macro like a function does not contain parentheses during use, the pre-processor only processes the macro as a general symbol (that is, not to handle it)

 

In order to automatically generate a lot of similar code, the function library uses a macro:

# Define ttl_func_build_functor_caller (N)/<br/> template <typename R, ttl_tparams (n)> /<br/> struct functor_caller_base # N/<br/> ///.... 

The final purpose of this macro is to automatically generate many functor_caller_base templates by calling methods similar to ttl_func_build_functor_caller (1:

Template <typename R, typename T1> struct functor_caller_base1 <br/> template <typename R, typename T1, typename T2> struct <br/> template <typename R, typename T1, typename T2> struct functor_caller_base3 <br/> ///... 

The core part of the macro is ttl_tparams (N). It can be seen that the macro eventually produces:

Typename T1

Typename T1, typename T2

Typename T1, typename T2, typename T3

///...

 

The analysis process is analyzed layer by layer. For example, ttl_tparams (1 ):

# Define ttl_tparams (n) ttl_tparamsx (n, T) <br/> => ttl_tparamsx (1, t) <br/> # define ttl_tparamsx (n, T) ttl_repeat (n, ttl_tparam, limit, T) <br/> => ttl_repeat (1, ttl_tparam, ttl_tparam_end, T) <br/> # define ttl_tparam (n, T) typename T # N, <br/> # define ttl_tparam_end (n, T) typename T # n <br/> # define ttl_repeat (n, m, L, P) ttl_append (ttl_repeat _, ttl_dec (N) (M, L, P) <br/> ttl_append (ttl_last_repeat _, n) (L, P) 

Note: Although ttl_tparam and ttl_tparam_end are two macros, they are used as parameters of the ttl_repeat macro. According to the prescan rules, it seems that the macro should be

Expand to ttl_repeat. However, as I mentioned earlier, these two macros are function-like macro, which must be enclosed in brackets. If no brackets are added, macro processing is not appropriate. Therefore, when expanding ttl_repeat, it should be:

=> Ttl_append (ttl_repeat _, ttl_dec (1) (ttl_param, ttl_tparam_end, T)

Ttl_append (ttl_last_repeat _, 1) (ttl_tparam_end, T)

This macro seems to be complicated. After careful analysis, it can be divided into two parts:

Ttl_append (ttl_repeat _, ttl_dec (1) (ttl_tparam_end, T) and

Ttl_append (ttl_last_repeat _, 1) (ttl_tparam_end, T)

First, analyze the first part:

# Define ttl_append (x, y) ttl_append1 (x, y) // expand X first, y then connect X and Y <br/> # define ttl_append1 (x, y) X # Y <br/> # define ttl_dec (n) ttl_append (ttl_cntdec _, n) 

According to the principle of expanding parameters first, ttl_dec (1) is expanded first)

=> Ttl_append (ttl_cntdec _, 1) => ttl_cntdec_1

# Define ttl_cntdec_1 0 // note that ttl_cntdec _ is not a macro and ttl_cntdec_1 is a macro 

=> 0, that is, ttl_dec (1) is finally expanded to 0, return to the ttl_append part:

=> Ttl_repeat_0 (ttl_tparam, ttl_tparam_end, T)

# Define ttl_repeat_0 (M, L, P) 

The macro ttl_repeat_0 is empty, so the first part mentioned above is ignored, and only the second part is left:

Ttl_append (ttl_last_repeat _, 1) (ttl_tparam_end, T)

=> Ttl_last_repeat_1 (ttl_tparam_end, T) // ttl_append combines ttl_last_repeat _ and 1

# Define ttl_last_repeat_1 (m, p) m (1, P) 

=> Ttl_tparam_end (1, t)

# Define ttl_tparam_end (n, T) typename T # N 

=> Typename T1 is expanded.

 

We should get the author's macro programming ideas from those macros. The good use of macros seems to be a miracle, but he does make our coding more automated.

 

Http://www.docin.com/p-56213848.html

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.