• 介绍一个C++奇巧淫技


    你能实现这样一个函数吗:

      MyType type;
      HisType htype;
      serialize_3(11, type, htype);
      serialize_4(type, htype ,type, htype);
      serialize_4(11, type , htype, htype);
    

    参数类型自由,个数自由,怎么做呢?往下看:


    [xiaochu.yh@OB macro]$ cat auto_type.cpp 
    /*
     * (C) 1999-2013 Alibaba Inc.
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     *
     *
     * Version:  auto_type.cpp,  09/04/2013 08:02:17 PM Yu Huang Exp $
     *
     * Author:
     *   Huang Yu <xiaochu.yh@alipay.com>
     * Description:
     *   auto type match
     *
     */
    
    #include <stdio.h>
    
    void serialize()
    {
      return;
    }
    
    class HisType
    {
      public:
        HisType(const char *i) : value_(i) { }
        ~HisType() { }
        void serialize() const
        {
          printf("HisType: s(%s)
    ", value_);
        }
      private:
        const char *value_;
    };
    
    class MyType
    {
      public:
        MyType(int i) : value_(i) { }
        ~MyType() { }
        void serialize() const
        {
          printf("MyType: f(%d)
    ", value_);
        }
      private:
        int value_;
    };
    
    void serialize(const int arg0)
    {
      printf("int: %d
    ", arg0);
    }
    void serialize(const float arg0)
    {
      printf("float: %f
    ", arg0);
    }
    
    template<typename Arg0>
    void serialize(const Arg0 &arg0)
    {
      arg0.serialize();
    }
    
    template<typename Arg0>
    void serialize_1(const Arg0 &arg0)
    {
      serialize(arg0);
    }
    
    #define JOIN(x,y) JOIN2(x,y)
    #define JOIN2(x,y) x##y
    
    #define DECVAL_1 0
    #define DECVAL_2 1
    #define DECVAL_3 2
    #define DECVAL_4 3
    #define DEC_VAL(n) DECVAL_##n
    
    // recursively expanding macro
    #define ARG_TN0
    #define ARG_TN1  typename Arg0
    #define ARG_TN2  ARG_TN1, typename Arg1
    #define ARG_TN3  ARG_TN2, typename Arg2
    #define ARG_TN4  ARG_TN3, typename Arg3
    
    #define ARG_PN0
    #define ARG_PN1  const Arg0 & arg0
    #define ARG_PN2  ARG_PN1, const Arg1 & arg1
    #define ARG_PN3  ARG_PN2, const Arg2 & arg2
    #define ARG_PN4  ARG_PN3, const Arg3 & arg3
    
    #define ARG_AN0
    #define ARG_AN1  arg0
    #define ARG_AN2  ARG_AN1, arg1
    #define ARG_AN3  ARG_AN2, arg2
    #define ARG_AN4  ARG_AN3, arg3
    
    
    #define ARG_CN0
    #define ARG_CN1  arg0
    #define ARG_CN2  arg1
    #define ARG_CN3  arg2
    #define ARG_CN4  arg3
    
    
    #define SERIALIZE_DECLARE(NUM_ARG) 
      template<JOIN(ARG_TN, NUM_ARG)> 
    void JOIN(serialize_, NUM_ARG)(JOIN(ARG_PN, NUM_ARG))
    
    SERIALIZE_DECLARE(2);
    SERIALIZE_DECLARE(3);
    SERIALIZE_DECLARE(4);
    #define SERIALIZE_DEFINE(NUM_ARG) 
      template<JOIN(ARG_TN, NUM_ARG)> 
    void JOIN(serialize_, NUM_ARG)(JOIN(ARG_PN, NUM_ARG)) 
    { 
      JOIN(serialize_, DEC_VAL(NUM_ARG))(JOIN(ARG_AN, DEC_VAL(NUM_ARG))); 
      serialize(JOIN(ARG_CN, NUM_ARG)); 
    }
    
    
    SERIALIZE_DEFINE(2);
    SERIALIZE_DEFINE(3);
    SERIALIZE_DEFINE(4);
    
    int main()
    {
      MyType type(4234);
      HisType htype("home");
      //先来个见面礼, 1是int类型,10.2f是float类型,type是自定义类型
      serialize_4(1,10.2f,3, type);
      printf("==============
    ");
      serialize_3(type,11, htype);  // <== 注意下面的参数个数,以及参数顺序,完全自由!
      printf("==============
    ");
      serialize_3(11 ,type, htype);
      printf("==============
    ");
      serialize_3(htype ,type, htype);
      printf("==============
    ");
      return 0;
    }


    编译运行结果:

    [xiaochu.yh@OB macro]$ g++ auto_type.cpp           
    [xiaochu.yh@OB]$ ./a.out 
    int: 1
    float: 10.200000
    int: 3
    MyType: f(4234)
    ==============
    MyType: f(4234)
    int: 11
    HisType: s(home)
    ==============
    int: 11
    MyType: f(4234)
    HisType: s(home)
    ==============
    HisType: s(home)
    MyType: f(4234)
    HisType: s(home)
    ==============
    


    该技术是从曲山同学的代码中学习来的,曲山对宏的运用真是炉火纯青!这里最神奇的就是下面一段代码,至今不明:

    #define JOIN(x,y) JOIN2(x,y)
    #define JOIN2(x,y) x##y

    JOIN和JOIN2不是等价的吗?不过还真不是。如果只写JOIN2,在宏展开阶段会有比较诡异的事情发生。不信你试试。但是为什么呢?我也不知道。@曲山,求助啊~~

    更全面的代码见OceanBase源码oceanbase/src/common/ob_rpc_stub.h和oceanbase/src/common/ob_rpc_macros.h


    =============================================

    UPDATE:

    这篇帖子发到了内网,得到了@探晴同学指点,加上@元启 同学的解释,基本弄明白了JOIN的机制。

    原因的确很简单。 
    #define MY_VALUE 2 
    #define JOIN(A,B) A##B
    JOIN(hello, world)的输出结果就是 helloworld,
    JOIN(MY_VALUE, b)的输出结果就是 MY_VALUEb。尽管MY_VALUE是个宏,你期待它展开成2b。

    如何成为一个2b呢? 这么做:
    #define JOIN(a, b) JOIN_EXPAND_PARAM(a,b)
    #define JOIN_EXPAND_PARAM(a,b) a##b

    JOIN(MY_VALUE, b)的展开过程是:
    1. JOIN(MY_VALUE, b)展开成 JOIN_EXPAND_PARAM(2, b)
    2. JOIN_EXPAND_PARAM(2, b) 展开成 2b

    这句话:Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens.

    参考: http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html


  • 相关阅读:
    JSP学习笔记(一):JSP语法和指令
    小知识随手记(五)
    jQuery序列化表单数据 serialize()、serializeArray()及使用
    Servlet学习笔记(三):HTTP请求与响应
    Servlet学习笔记(二):表单数据
    AJAX前台传过来的中文在后台获取是乱码问题
    Servlet学习笔记(一):生命周期
    Servlet介绍以及简单实例
    jsp+servlet+jdbc实现对数据库的增删改查
    UML类图符号解释
  • 原文地址:https://www.cnblogs.com/pangblog/p/3304100.html
Copyright © 2020-2023  润新知