如何解读fast-lio2中的 `IKFoM` 中的宏定义

1,488 阅读16分钟

标题: 如何解读fast-lio2中的IKFoM中的宏定义

作者: 边城量子 ( shihezichen@live.cn )


KeyMessage 1: 本文讲解如何解析 fast-lio2 中的 IKFOM 的宏定义.

KeyMessage 2: 本文中一开始有较多宏解析过程的介绍, 若想直接看解析后的结果, 可以根据右边侧边栏上的 目录导引直接跳转到对应的章节, 如"Step1..." 、"Step2..."、"Step3..." 看最后解析完毕的C++代码.

Keymessage 3: 编写宏时, 会涉及大量boost的宏模板编程技术, 如BOOST_PP_SEQ_xxx 等; 但是在解读宏代码时, 则不需要了解太多 boost 的技术。 本文无需涉及 boost 库即可解读宏代码.

现象 : build_manifold.hpp 中存在大量的宏定义

  • 文件中定义了大量的宏,举例如下:

    #ifndef PARSED_BY_DOXYGEN
    //////// internals //////
    #define MTK_APPLY_MACRO_ON_TUPLE(r, macro, tuple) macro tuple
    #define MTK_TRANSFORM_COMMA(macro, entries) BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM_S(1, MTK_APPLY_MACRO_ON_TUPLE, macro, entries))
    ...
    
    • 其中的代码 #ifndef PARSED_BY_DOXYGEN 表示接下来的代码,将不是由 DOXYGEN 工具来解析,而是由C++预处理来处理
    • 所谓的C++预处理来处理,即使用宏定义展开的方式来生成代码
    • 大量使用到了Boost库的预处理(PP: preprocessor)模板元库的宏定义, 例如 BOOST_PP_SEQ_ENUM 宏用来将一个序列转换成数组, BOOST_PP_SEQ_TRANSFORM_S 宏则用来产生一个序列.
    • 这些宏层层嵌套引用, 最终组成了若干个更大的宏定义, 例如:
       MTK_BUILD_MANIFOLD
    

    暂时先不需要细究 build_manifold.hpp 中的代码中宏定义细节, 也不需要去深究其中Boost的预处理宏模板元编程细节.

    只需要知道此文件中定义的是一堆宏定义即可,我们后续将使用一些方法,把宏展开(包括boost宏),那时就可以看得更清楚;

问题 : 谁在使用build_mainfold.hpp中的宏定义?

现已知build_mainfold.hpp 是个充满了宏定义的头文件,那又是谁使用到了它?

  • 通过走读代码, 发现使用到 build_manifold.hpp 的是 use-ikfom.hpp 文件
  • use-ikfom.hpp 中有如下代码:
    typedef MTK::vect<3, double> vect3;
    typedef MTK::SO3<double> SO3;
    typedef MTK::S2<double, 98090, 10000, 1> S2; 
    typedef MTK::vect<1, double> vect1;
    typedef MTK::vect<2, double> vect2;
    
    MTK_BUILD_MANIFOLD(state_ikfom,
    ((vect3, pos))
    ((SO3, rot))
    ((SO3, offset_R_L_I))
    ((vect3, offset_T_L_I))
    ((vect3, vel))
    ((vect3, bg))
    ((vect3, ba))
    ((S2, grav))
    );
    
    MTK_BUILD_MANIFOLD(input_ikfom,
    ((vect3, acc))
    ((vect3, gyro))
    );
    
    ...
    
    • 可以看出,use-ikfom.hpp 代码中, 在不断的使用 MTK_BUILD_MANIFOLD 宏来生成代码
    • 当某个文件包含了 use-ikfom.hpp 时,这些宏就会被展开对应的c++代码
    • 通过查看代码可以发现,使用了 use-ikfom.hpp 的是 IMU_Processing.hpp 文件

问题: 如何展开use-ikfom.hpp中的宏?

如何展开use-ikfom.hpp中的宏, 看到其对应的C++代码的样子?

使用手工逐个从底层宏到上层宏, 做宏展开, 这当然是一种手段, 但这种方法费时费力, 且容易出错, 此处不予考虑。

下面将使用C++预处理能力的方式展开宏, 相比之下较为自动和准确。分为如下几个环节:

  • 第一个环节: 准备宏代码分析的Project和相关的小工具代码

    • Step 1: 使用IDE建立一个最简单的C++工程, 把 include 目录下的文件都放进去

      备注: 下图中红色框起来的四个文件是新增的文件, 其余的均为fast-lio2 已有的文件. 新增的文件此时还不存在, 可先添加其余的文件. image.png

    • Step 2: 为避免IDE编译时报错,需再建立一个 main.cpp 文件, 里面存放 main() 函数。 由于我们只需要做编译期推导,因此函数内部可以没有实现, 如下:

    #include "use-ikfom.hpp"
    int main()
    {
        return 0;
    }
    
    • Step 3: 再准备一些宏展开的小工具,本质上是一些辅助宏解析和展示的C++代码, 放入到main.cpp文件中, 此时 main.cpp 变为:
    #include "use-ikfom.hpp"
    
    // 定义用于显示宏内容的宏代码
    #define M(x) #x
    #define DIS(x) #x"=>\n\t"M(x)
    
    // Start: 如下区域用于对IKFoM的宏进行展开
    
    // End
    
    int main()
    {
        return 0;
    }
    

    备注: 以上用到了宏的基本知识, 例如#等。 若需对C++宏的基本概念有进一步理解, 可参见帖子: C/C++宏基本概念

  • 第二个环节,准备C++代码格式化工具:

    主要目的是用于对C++代码进行格式化,使之可读。

    可以使用IDE的代码格式化功能,或者在线的代码格式化功能,例如: tools.jb51.net/code/jb51_c…

开始解析

准备工作完成后, 就可以开始解析 IKFoM 中的宏了。

build_mainfold.hpp中, 有如下三段宏, 下面会分别进行展开:

  MTK_BUILD_MANIFOLD(input_ikfom,
    ((vect3, acc))
    ((vect3, gyro))
    );
    
  MTK_BUILD_MANIFOLD(state_ikfom,
    ((vect3, pos))
    ((SO3, rot))
    ((SO3, offset_R_L_I))
    ((vect3, offset_T_L_I))
    ((vect3, vel))
    ((vect3, bg))
    ((vect3, ba))
    ((S2, grav))
    );   
    
    MTK_BUILD_MANIFOLD(process_noise_ikfom,
    ((vect3, ng))
    ((vect3, na))
    ((vect3, nbg))
    ((vect3, nba))
    );
Step1:解析 input_ikfom 对应的宏

use-ikfom.hpp 中的存在如下宏定义的原始代码片段:

MTK_BUILD_MANIFOLD(input_ikfom,
  ((vect3, acc))
  ((vect3, gyro))
  );

它宏展开是怎样的形式呢?

可在 main.cppStartEnd 区域中增加宏展开语句, 新增的代码如下形式:

  // Start: 如下区域用于对IKFoM的宏进行展开
  #pragma message(DIS( \
    MTK_BUILD_MANIFOLD(input_ikfom,  \
    ((vect3, acc))  \
    ((vect3, gyro))  \
    )  \
  ))
  // End
  • 可以看到,代码本质是把宏定义放到 #pragma message(DIS( )) 中进行展开
  • 针对以上代码进行编译(注意是编译并不链接,如果是gcc可以用gcc –E),以看到编译阶段的输出如下:
MTK_BUILD_MANIFOLD(input_ikfom, ((vect3, acc)) ((vect3, gyro)) )=>
struct input_ikfom { typedef input_ikfom self; std::vector<std::pair<int, int> > S2_state; std::vector<std::pair<int, int> > SO3_state; std::vector<std::pair<std::pair<int, int>, int> > vect_state; MTK_ENTRIES_OUTPUT_I ( 2, (vect3, acc) , ((vect3, gyro)) (~), 0, 0, S2_state, SO3_state ) MTK_ENTRIES_OUTPUT_I ( 1, (vect3, gyro) ,  (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DIM, S2_state, SO3_state)   input_ikfom ( BOOST_PP_SEQ_ENUM_2  (const vect3& acc = vect3()) (const vect3& gyro = vect3()) ) : BOOST_PP_SEQ_ENUM_2  (acc(acc)) (gyro(gyro)) {} int getDOF() const { return DOF; } void boxplus(const MTK::vectview<const scalar, DOF> & __vec, scalar __scale = 1 ) { MTK_BOXPLUS (vect3, acc)  MTK_BOXPLUS (vect3, gyro)    } void oplus(const MTK::vectview<const scalar, DIM> & __vec, scalar __scale = 1 ) { MTK_OPLUS (vect3, acc)  MTK_OPLUS (vect3, gyro)    } void boxminus(MTK::vectview<scalar,DOF> __res, const input_ikfom& __oth) const { MTK_BOXMINUS (vect3, acc)  MTK_BOXMINUS (vect3, gyro)    } friend std::ostream& operator<<(std::ostream& __os, const input_ikfom& __var){ return __os MTK_OSTREAM (vect3, acc)  MTK_OSTREAM (vect3, gyro)   ; } void build_S2_state(){ MTK_S2_state (vect3, acc)  MTK_S2_state (vect3, gyro)    } void build_vect_state(){ MTK_vect_state (vect3, acc)  MTK_vect_state (vect3, gyro)    } void build_SO3_state(){ MTK_SO3_state (vect3, acc)  MTK_SO3_state (vect3, gyro)    } void S2_hat(Eigen::Matrix<scalar, 3, 3> &res, int idx) { MTK_S2_hat (vect3, acc)  MTK_S2_hat (vect3, gyro)    } void S2_Nx_yy(Eigen::Matrix<scalar, 2, 3> &res, int idx) { MTK_S2_Nx_yy (vect3, acc)  MTK_S2_Nx_yy (vect3, gyro)    } void S2_Mx(Eigen::Matrix<scalar, 3, 2> &res, Eigen::Matrix<scalar, 2, 1> dx, int idx) { MTK_S2_Mx (vect3, acc)  MTK_S2_Mx (vect3, gyro)    } friend std::istream& operator>>(std::istream& __is, input_ikfom& __var){ return __is MTK_ISTREAM (vect3, acc)  MTK_ISTREAM (vect3, gyro)   ; } };
  • 上文的第二行C++代码是比较长的,把它拷贝出来,并使用代码格式化工具进行格式化,可知其对应如下代码:
struct input_ikfom 
{
  typedef input_ikfom self;
  std::vector<std::pair<int, int> > S2_state;
  std::vector<std::pair<int, int> > SO3_state;
  std::vector<std::pair<std::pair<int, int>, int> > vect_state;
  MTK_ENTRIES_OUTPUT_I ( 2, (vect3, acc) , ((vect3, gyro)) (~), 0, 0, S2_state, SO3_state )         
  MTK_ENTRIES_OUTPUT_I ( 1, (vect3, gyro) ,  (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DIM, S2_state, SO3_state)   
  input_ikfom ( BOOST_PP_SEQ_ENUM_2  (const vect3& acc = vect3()) (const vect3& gyro = vect3()) ) : BOOST_PP_SEQ_ENUM_2  (acc(acc)) (gyro(gyro)) 
  {
  }
  int getDOF() const 
  {
  	return DOF;
  }
  void boxplus(const MTK::vectview<const scalar, DOF> & __vec, scalar __scale = 1 ) 
  {
  	MTK_BOXPLUS (vect3, acc)  MTK_BOXPLUS (vect3, gyro)
  }
  void oplus(const MTK::vectview<const scalar, DIM> & __vec, scalar __scale = 1 ) 
  {
  	MTK_OPLUS (vect3, acc)  MTK_OPLUS (vect3, gyro)
  }
  void boxminus(MTK::vectview<scalar,DOF> __res, const input_ikfom& __oth) const 
  {
  	MTK_BOXMINUS (vect3, acc)  MTK_BOXMINUS (vect3, gyro)
  }
  friend std::ostream& operator<<(std::ostream& __os, const input_ikfom& __var) 
  {
  	return __os MTK_OSTREAM (vect3, acc)  MTK_OSTREAM (vect3, gyro)   ;
  }
  void build_S2_state() 
  {
  	MTK_S2_state (vect3, acc)  MTK_S2_state (vect3, gyro)
  }
  void build_vect_state() 
  {
  	MTK_vect_state (vect3, acc)  MTK_vect_state (vect3, gyro)
  }
  void build_SO3_state() 
  {
  	MTK_SO3_state (vect3, acc)  MTK_SO3_state (vect3, gyro)
  }
  void S2_hat(Eigen::Matrix<scalar, 3, 3> &res, int idx) 
  {
  	MTK_S2_hat (vect3, acc)  MTK_S2_hat (vect3, gyro)
  }
  void S2_Nx_yy(Eigen::Matrix<scalar, 2, 3> &res, int idx) 
  {
  	MTK_S2_Nx_yy (vect3, acc)  MTK_S2_Nx_yy (vect3, gyro)
  }
  void S2_Mx(Eigen::Matrix<scalar, 3, 2> &res, Eigen::Matrix<scalar, 2, 1> dx, int idx) 
  {
  	MTK_S2_Mx (vect3, acc)  MTK_S2_Mx (vect3, gyro)
  }
  friend std::istream& operator>>(std::istream& __is, input_ikfom& __var) 
  {
  	return __is MTK_ISTREAM (vect3, acc)  MTK_ISTREAM (vect3, gyro)   ;
  }
};
  • 这段代码本质上是定义了一个 struct, 名为 input_ikfom

  • 在结构体中定义了一些成员变量, 如 S2_stateSO3_state 等, 还定义了一些方法,如 boxplusoplusbuild_SO3_stateS2_hat

  • 遗留问题: 可以看到,生成的代码中, 依然还有一些深层次宏并没有被展开,例如 MTK_ENTRIES_OUTPUT_IBOOST_PP_SEQ_ENUM_2BOOST_PP_TUPLE_ELEM_2_0MTK_BOXPLUS等. 原因是编译器在编译期进行宏展开时,如果遇到参数中宏定义有#或##符号进行连接时, 就会停止这一层的宏展开.

  • 如何解决? 没关系, 针对这种情况, 依然可以继续使用上面的方法来针对它们特别处理,例如:

    • 举例 1:

    宏的原代码:

    MTK_ENTRIES_OUTPUT_I ( 2, (vect3, acc) , ((vect3, gyro)) (~), 0, 0, S2_state, SO3_state )  
    

    使用上述相同的宏展开方法, 可以得到以上宏最终的C++代码如下(注: 宏展开可能会多次递归).

    MTK::SubManifold<vect3, 0, 0> acc;
    

    可知这是一个加速度的类成员变量定义, 类型为 MTK::SubManifold<vect3, 0, 0>

    • 举例 2 :I

    原代码:

    MTK_ENTRIES_OUTPUT_I ( 1, (vect3, gyro) ,  (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DIM, S2_state, SO3_state) 
    

    上述宏定义最终对应的C++代码为:

    MTK::SubManifold<vect3, 0 + vect3::DOF, 0 + vect3::DIM> gyro;
    enum { DOF = vect3::DOF + 0 + vect3::DOF   };
    enum { DIM = vect3::DIM + 0 + vect3::DIM   };
    typedef vect3::scalar scalar;
    

    可知, 这段代码定义了 gyro 成员变量和 DOF, DIM 枚举值, 以及定义了 scalar 数据类型.

    • 举例 3: 原代码:
    input_ikfom ( BOOST_PP_SEQ_ENUM_2 (const vect3& acc = vect3()) (const vect3& gyro = vect3()) ) : BOOST_PP_SEQ_ENUM_2 (acc(acc)) (gyro(gyro)) { }
    

    上述宏定义最终对应的C++代码为:

    input_ikfom(const vect3& acc = vect3(), const vect3& gyro = vect3()) : acc(acc), gyro(gyro) 
    { 
    }      
    

    可知, 这段代码定义了一个构造函数

    • 举例 : 其他的宏

      与上述举例类似, 均为重复性工作, 此处不再赘述

Step1 的解析结果
  • 最终可以得到对应的C++代码片段如下:

    宏的原代码:

    MTK_BUILD_MANIFOLD(input_ikfom,
        ((vect3, acc))
        ((vect3, gyro))
    );
    

    宏展开后 对应的C++代码如下:

    注: 可以看到, 这段宏, 定义了一个 struct, 名称为 input_ikfom, 成员变量有两个 acc, gyro, 并且自动生成了 ,\boxplus, \boxminus 等运算对应的成员函数

    struct input_ikfom
    {
        typedef input_ikfom self;
        std::vector<std::pair<int, int> > S2_state;
        std::vector<std::pair<int, int> > SO3_state;
        std::vector<std::pair<std::pair<int, int>, int> > vect_state;
        //MTK_ENTRIES_OUTPUT_I ( 2, (vect3, acc) , ((vect3, gyro)) (~), 0, 0, S2_state, SO3_state )         
        MTK::SubManifold<vect3, 0, 0> acc;
        //MTK_ENTRIES_OUTPUT_I ( 1, (vect3, gyro) ,  (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, acc)::DIM, S2_state, SO3_state)   
        MTK::SubManifold<vect3, 0 + vect3::DOF, 0 + vect3::DIM> gyro;
        enum { DOF = vect3::DOF + 0 + vect3::DOF };
        enum { DIM = vect3::DIM + 0 + vect3::DIM };
    
        typedef vect3::scalar scalar;
            
        // input_ikfom ( BOOST_PP_SEQ_ENUM_2  (const vect3& acc = vect3()) (const vect3& gyro = vect3()) ) : BOOST_PP_SEQ_ENUM_2  (acc(acc)) (gyro(gyro)) 
        input_ikfom(const vect3& acc = vect3(), const vect3& gyro = vect3()) : acc(acc), gyro(gyro)
        {
        }
        int getDOF() const
        {
            return DOF;
        }
        void boxplus(const MTK::vectview<const scalar, DOF>& __vec, scalar __scale = 1)
        {
            //MTK_BOXPLUS(vect3, acc)  MTK_BOXPLUS(vect3, gyro)
            acc.boxplus(MTK::subvector(__vec, &self::acc), __scale); 
            gyro.boxplus(MTK::subvector(__vec, &self::gyro), __scale);
        }
        void oplus(const MTK::vectview<const scalar, DIM>& __vec, scalar __scale = 1)
        {
            //MTK_OPLUS(vect3, acc)  MTK_OPLUS(vect3, gyro)
            acc.oplus(MTK::subvector_(__vec, &self::acc), __scale); 
            gyro.oplus(MTK::subvector_(__vec, &self::gyro), __scale);
        }
        void boxminus(MTK::vectview<scalar, DOF> __res, const input_ikfom& __oth) const
        {
            //MTK_BOXMINUS(vect3, acc)  MTK_BOXMINUS(vect3, gyro)
            acc.boxminus(MTK::subvector(__res, &self::acc), __oth.acc); 
            gyro.boxminus(MTK::subvector(__res, &self::gyro), __oth.gyro);
        }
        friend std::ostream& operator<<(std::ostream& __os, const input_ikfom& __var)
        {
            //return __os MTK_OSTREAM(vect3, acc)  MTK_OSTREAM(vect3, gyro);
            return __os << __var.acc << " " << __var.gyro << " ";
        }
        void build_S2_state()
        {
            //MTK_S2_state(vect3, acc)  MTK_S2_state(vect3, gyro)
            if (acc.TYP == 1)
            {
                S2_state.push_back(std::make_pair(acc.IDX, acc.DIM));
            }
            if (gyro.TYP == 1)
            {
                S2_state.push_back(std::make_pair(gyro.IDX, gyro.DIM));
            }
        }
        void build_vect_state()
        {
            //MTK_vect_state(vect3, acc)  MTK_vect_state(vect3, gyro)
            if (acc.TYP == 0)
            {
                (vect_state).push_back(std::make_pair(std::make_pair(acc.IDX, acc.DIM), vect3::DOF));
            }
            if (gyro.TYP == 0)
            {
                (vect_state).push_back(std::make_pair(std::make_pair(gyro.IDX, gyro.DIM), vect3::DOF));
            }
        }
        void build_SO3_state()
        {
            //MTK_SO3_state(vect3, acc)  MTK_SO3_state(vect3, gyro)
            if (acc.TYP == 2)
            {
                (SO3_state).push_back(std::make_pair(acc.IDX, acc.DIM));
            }
            if (gyro.TYP == 2)
            {
                (SO3_state).push_back(std::make_pair(gyro.IDX, gyro.DIM));
            }
        }
        void S2_hat(Eigen::Matrix<scalar, 3, 3>& res, int idx)
        {
            //MTK_S2_hat(vect3, acc)  MTK_S2_hat(vect3, gyro)
            if (acc.IDX == idx)
            {
                    acc.S2_hat(res);
            }
            if (gyro.IDX == idx)
            {
                    gyro.S2_hat(res);
            }
        }
        void S2_Nx_yy(Eigen::Matrix<scalar, 2, 3>& res, int idx)
        {
            //MTK_S2_Nx_yy(vect3, acc)  MTK_S2_Nx_yy(vect3, gyro)
            if (acc.IDX == idx)
            {
                    acc.S2_Nx_yy(res);
            }
            if (gyro.IDX == idx)
            {
                    gyro.S2_Nx_yy(res);
            }
        }
        void S2_Mx(Eigen::Matrix<scalar, 3, 2>& res, Eigen::Matrix<scalar, 2, 1> dx, int idx)
        {
            //MTK_S2_Mx(vect3, acc)  MTK_S2_Mx(vect3, gyro)
            if (acc.IDX == idx)
            {
                acc.S2_Mx(res, dx);
            }
            if (gyro.IDX == idx)
            {
                gyro.S2_Mx(res, dx);
            }
        }
        friend std::istream& operator>>(std::istream& __is, input_ikfom& __var)
        {
            //return __is MTK_ISTREAM(vect3, acc)  MTK_ISTREAM(vect3, gyro);
            return __is >> __var.acc >> __var.gyro;
        }
    };
    
Step2:解析 state_ikfom 对应的宏

use-ikfom.hpp 中的如下宏定义代码代码片段为例:

MTK_BUILD_MANIFOLD(state_ikfom,
((vect3, pos))
((SO3, rot))
((SO3, offset_R_L_I))
((vect3, offset_T_L_I))
((vect3, vel))
((vect3, bg))
((vect3, ba))
((S2, grav))
);

依照上述办法解析.不再赘述.

Step2 的解析结果

对应的代码片段为:

struct state_ikfom 
{
  typedef state_ikfom self;
  std::vector<std::pair<int, int> > S2_state;
  std::vector<std::pair<int, int> > SO3_state;
  std::vector<std::pair<std::pair<int, int>, int> > vect_state;
  //MTK_ENTRIES_OUTPUT_I ( 8, (vect3, pos) , ((SO3, rot)) ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0, 0, S2_state, SO3_state ) 
  MTK::SubManifold<vect3, 0, 0> pos;
  
  //MTK_ENTRIES_OUTPUT_I ( 7, (SO3, rot) ,  ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, pos)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, pos)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I ( 6, (SO3, offset_R_L_I) ,  ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (SO3, rot)::DOF, 0 + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (SO3, rot)::DIM, S2_state, SO3_state) 
  MTK::SubManifold<SO3, 0 + vect3::DOF, 0 + vect3::DIM> rot; 
  MTK::SubManifold<SO3, 0 + vect3::DOF + SO3::DOF, 0 + vect3::DIM + SO3::DIM> offset_R_L_I;
  
  //MTK_ENTRIES_OUTPUT_I ( 5, (vect3, offset_T_L_I) ,  ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (SO3, offset_R_L_I)::DOF, 0 + vect3::DIM + SO3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (SO3, offset_R_L_I)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I ( 4, (vect3, vel) ,  ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, offset_T_L_I)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, offset_T_L_I)::DIM, S2_state, SO3_state) 
  MTK::SubManifold<vect3, 0 + vect3::DOF + SO3::DOF + SO3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM> offset_T_L_I; 
  MTK::SubManifold<vect3, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM> vel;

  //MTK_ENTRIES_OUTPUT_I ( 3, (vect3, bg) ,  ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, vel)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, vel)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I ( 2, (vect3, ba) ,  ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, bg)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, bg)::DIM, S2_state, SO3_state) 
  MTK::SubManifold<vect3, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM> bg; 
  MTK::SubManifold<vect3, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM> ba;
  
  //MTK_ENTRIES_OUTPUT_I ( 1, (S2, grav) ,  (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, ba)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, ba)::DIM, S2_state, SO3_state)   
  MTK::SubManifold<S2, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM + vect3::DIM> grav; 
  enum {DOF = S2::DOF + 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF + vect3::DOF}; 
  enum {DIM = S2::DIM+0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM + vect3::DIM}; 
  typedef S2::scalar scalar;

  //state_ikfom ( BOOST_PP_SEQ_ENUM_8  (const vect3& pos = vect3()) (const SO3& rot = SO3()) (const SO3& offset_R_L_I = SO3()) (const vect3& offset_T_L_I = vect3()) (const vect3& vel = vect3()) (const vect3& bg = vect3()) (const vect3& ba = vect3()) (const S2& grav = S2()) ) : BOOST_PP_SEQ_ENUM_8  (pos(pos)) (rot(rot)) (offset_R_L_I(offset_R_L_I)) (offset_T_L_I(offset_T_L_I)) (vel(vel)) (bg(bg)) (ba(ba)) (grav(grav)) 
  state_ikfom(const vect3& pos = vect3(), const SO3& rot = SO3(), const SO3& offset_R_L_I = SO3(), const vect3& offset_T_L_I = vect3(), const vect3& vel = vect3(), const vect3& bg = vect3(), const vect3& ba = vect3(), const S2& grav = S2()) : pos(pos), rot(rot), offset_R_L_I(offset_R_L_I), offset_T_L_I(offset_T_L_I), vel(vel), bg(bg), ba(ba), grav(grav)
  {
  }
  int getDOF() const 
  {
    return DOF;
  }
  void boxplus(const MTK::vectview<const scalar, DOF> & __vec, scalar __scale = 1 ) 
  {
    //MTK_BOXPLUS (vect3, pos)  MTK_BOXPLUS (SO3, rot)  MTK_BOXPLUS (SO3, offset_R_L_I)  MTK_BOXPLUS (vect3, offset_T_L_I)  MTK_BOXPLUS (vect3, vel)  MTK_BOXPLUS (vect3, bg)  MTK_BOXPLUS (vect3, ba)  MTK_BOXPLUS (S2, grav)
    pos.boxplus(MTK::subvector(__vec, &self::pos), __scale); 
    rot.boxplus(MTK::subvector(__vec, &self::rot), __scale); 
    offset_R_L_I.boxplus(MTK::subvector(__vec, &self::offset_R_L_I), __scale); 
    offset_T_L_I.boxplus(MTK::subvector(__vec, &self::offset_T_L_I), __scale); 
    vel.boxplus(MTK::subvector(__vec, &self::vel), __scale); 
    bg.boxplus(MTK::subvector(__vec, &self::bg), __scale); 
    ba.boxplus(MTK::subvector(__vec, &self::ba), __scale); 
    grav.boxplus(MTK::subvector(__vec, &self::grav), __scale);
  }
  void oplus(const MTK::vectview<const scalar, DIM> & __vec, scalar __scale = 1 ) 
  {
    //MTK_OPLUS (vect3, pos)  MTK_OPLUS (SO3, rot)  MTK_OPLUS (SO3, offset_R_L_I)  MTK_OPLUS (vect3, offset_T_L_I)  MTK_OPLUS (vect3, vel)  MTK_OPLUS (vect3, bg)  MTK_OPLUS (vect3, ba)  MTK_OPLUS (S2, grav)
    pos.oplus(MTK::subvector_(__vec, &self::pos), __scale); 
    rot.oplus(MTK::subvector_(__vec, &self::rot), __scale); 
    offset_R_L_I.oplus(MTK::subvector_(__vec, &self::offset_R_L_I), __scale); 
    offset_T_L_I.oplus(MTK::subvector_(__vec, &self::offset_T_L_I), __scale); 
    vel.oplus(MTK::subvector_(__vec, &self::vel), __scale); 
    bg.oplus(MTK::subvector_(__vec, &self::bg), __scale); 
    ba.oplus(MTK::subvector_(__vec, &self::ba), __scale); 
    grav.oplus(MTK::subvector_(__vec, &self::grav), __scale);
  }
  void boxminus(MTK::vectview<scalar,DOF> __res, const state_ikfom& __oth) const 
  {
    //MTK_BOXMINUS (vect3, pos)  MTK_BOXMINUS (SO3, rot)  MTK_BOXMINUS (SO3, offset_R_L_I)  MTK_BOXMINUS (vect3, offset_T_L_I)  MTK_BOXMINUS (vect3, vel)  MTK_BOXMINUS (vect3, bg)  MTK_BOXMINUS (vect3, ba)  MTK_BOXMINUS (S2, grav)
    pos.boxminus(MTK::subvector(__res, &self::pos), __oth.pos); 
    rot.boxminus(MTK::subvector(__res, &self::rot), __oth.rot); 
    offset_R_L_I.boxminus(MTK::subvector(__res, &self::offset_R_L_I), __oth.offset_R_L_I); 
    offset_T_L_I.boxminus(MTK::subvector(__res, &self::offset_T_L_I), __oth.offset_T_L_I); 
    vel.boxminus(MTK::subvector(__res, &self::vel), __oth.vel); 
    bg.boxminus(MTK::subvector(__res, &self::bg), __oth.bg); 
    ba.boxminus(MTK::subvector(__res, &self::ba), __oth.ba); 
    grav.boxminus(MTK::subvector(__res, &self::grav), __oth.grav);
  }
  friend std::ostream& operator<<(std::ostream& __os, const state_ikfom& __var) 
  {
    //return __os MTK_OSTREAM (vect3, pos)  MTK_OSTREAM (SO3, rot)  MTK_OSTREAM (SO3, offset_R_L_I)  MTK_OSTREAM (vect3, offset_T_L_I)  MTK_OSTREAM (vect3, vel)  MTK_OSTREAM (vect3, bg)  MTK_OSTREAM (vect3, ba)  MTK_OSTREAM (S2, grav)   ;
    return __os << __var.pos << " " << __var.rot << " " << __var.offset_R_L_I << " " << __var.offset_T_L_I << " " << __var.vel << " " << __var.bg << " " << __var.ba << " " << __var.grav << " ";
  }
  void build_S2_state() 
  {
    //MTK_S2_state (vect3, pos)  MTK_S2_state (SO3, rot)  MTK_S2_state (SO3, offset_R_L_I)  MTK_S2_state (vect3, offset_T_L_I)  MTK_S2_state (vect3, vel)  MTK_S2_state (vect3, bg)  MTK_S2_state (vect3, ba)  MTK_S2_state (S2, grav)
    if(pos.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(pos.IDX, pos.DIM));
    }
    if(rot.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(rot.IDX, rot.DIM));
    }
    if(offset_R_L_I.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(offset_R_L_I.IDX, offset_R_L_I.DIM));
    }
    if(offset_T_L_I.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(offset_T_L_I.IDX, offset_T_L_I.DIM));
    }
    if(vel.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(vel.IDX, vel.DIM));
    }
    if(bg.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(bg.IDX, bg.DIM));
    }
    if(ba.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(ba.IDX, ba.DIM));
    }
    if(grav.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(grav.IDX, grav.DIM));
    }
  }
  void build_vect_state() 
  {
    //MTK_vect_state (vect3, pos)  MTK_vect_state (SO3, rot)  MTK_vect_state (SO3, offset_R_L_I)  MTK_vect_state (vect3, offset_T_L_I)  MTK_vect_state (vect3, vel)  MTK_vect_state (vect3, bg)  MTK_vect_state (vect3, ba)  MTK_vect_state (S2, grav)
    if(pos.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(pos.IDX, pos.DIM), vect3::DOF));
    }
    if(rot.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(rot.IDX, rot.DIM), SO3::DOF));
    }
    if(offset_R_L_I.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(offset_R_L_I.IDX, offset_R_L_I.DIM), SO3::DOF));
    }
    if(offset_T_L_I.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(offset_T_L_I.IDX, offset_T_L_I.DIM), vect3::DOF));
    }
    if(vel.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(vel.IDX, vel.DIM), vect3::DOF));
    }
    if(bg.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(bg.IDX, bg.DIM), vect3::DOF));
    }
    if(ba.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(ba.IDX, ba.DIM), vect3::DOF));
    }
    if(grav.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(grav.IDX, grav.DIM), S2::DOF));
    }		
  }
  void build_SO3_state() 
  {
    //MTK_SO3_state (vect3, pos)  MTK_SO3_state (SO3, rot)  MTK_SO3_state (SO3, offset_R_L_I)  MTK_SO3_state (vect3, offset_T_L_I)  MTK_SO3_state (vect3, vel)  MTK_SO3_state (vect3, bg)  MTK_SO3_state (vect3, ba)  MTK_SO3_state (S2, grav)
    if(pos.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(pos.IDX, pos.DIM));
    }
    if(rot.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(rot.IDX, rot.DIM));
    }
    if(offset_R_L_I.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(offset_R_L_I.IDX, offset_R_L_I.DIM));
    }
    if(offset_T_L_I.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(offset_T_L_I.IDX, offset_T_L_I.DIM));
    }
    if(vel.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(vel.IDX, vel.DIM));
    }
    if(bg.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(bg.IDX, bg.DIM));
    }
    if(ba.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(ba.IDX, ba.DIM));
    }
    if(grav.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(grav.IDX, grav.DIM));
    }
  }
  void S2_hat(Eigen::Matrix<scalar, 3, 3> &res, int idx) 
  {
    //MTK_S2_hat (vect3, pos)  MTK_S2_hat (SO3, rot)  MTK_S2_hat (SO3, offset_R_L_I)  MTK_S2_hat (vect3, offset_T_L_I)  MTK_S2_hat (vect3, vel)  MTK_S2_hat (vect3, bg)  MTK_S2_hat (vect3, ba)  MTK_S2_hat (S2, grav)
    if(pos.IDX == idx) 
    {
      pos.S2_hat(res);
    }
    if(rot.IDX == idx) 
    {
      rot.S2_hat(res);
    }
    if(offset_R_L_I.IDX == idx) 
    {
      offset_R_L_I.S2_hat(res);
    }
    if(offset_T_L_I.IDX == idx) 
    {
      offset_T_L_I.S2_hat(res);
    }
    if(vel.IDX == idx) 
    {
      vel.S2_hat(res);
    }
    if(bg.IDX == idx) 
    {
      bg.S2_hat(res);
    }
    if(ba.IDX == idx) 
    {
      ba.S2_hat(res);
    }
    if(grav.IDX == idx) 
    {
      grav.S2_hat(res);
    }
  }
  void S2_Nx_yy(Eigen::Matrix<scalar, 2, 3> &res, int idx) 
  {
    //MTK_S2_Nx_yy (vect3, pos)  MTK_S2_Nx_yy (SO3, rot)  MTK_S2_Nx_yy (SO3, offset_R_L_I)  MTK_S2_Nx_yy (vect3, offset_T_L_I)  MTK_S2_Nx_yy (vect3, vel)  MTK_S2_Nx_yy (vect3, bg)  MTK_S2_Nx_yy (vect3, ba)  MTK_S2_Nx_yy (S2, grav)
    if(pos.IDX == idx) 
    {
      pos.S2_Nx_yy(res);
    }
    if(rot.IDX == idx) 
    {
      rot.S2_Nx_yy(res);
    }
    if(offset_R_L_I.IDX == idx) 
    {
      offset_R_L_I.S2_Nx_yy(res);
    }
    if(offset_T_L_I.IDX == idx) 
    {
      offset_T_L_I.S2_Nx_yy(res);
    }
    if(vel.IDX == idx) 
    {
      vel.S2_Nx_yy(res);
    }
    if(bg.IDX == idx) 
    {
      bg.S2_Nx_yy(res);
    }
    if(ba.IDX == idx) 
    {
      ba.S2_Nx_yy(res);
    }
    if(grav.IDX == idx) 
    {
      grav.S2_Nx_yy(res);
    }
  }
  void S2_Mx(Eigen::Matrix<scalar, 3, 2> &res, Eigen::Matrix<scalar, 2, 1> dx, int idx) 
  {
    //MTK_S2_Mx (vect3, pos)  MTK_S2_Mx (SO3, rot)  MTK_S2_Mx (SO3, offset_R_L_I)  MTK_S2_Mx (vect3, offset_T_L_I)  MTK_S2_Mx (vect3, vel)  MTK_S2_Mx (vect3, bg)  MTK_S2_Mx (vect3, ba)  MTK_S2_Mx (S2, grav)
    if(pos.IDX == idx) 
    {
      pos.S2_Mx(res, dx);
    }
    if(rot.IDX == idx) 
    {
      rot.S2_Mx(res, dx);
    }
    if(offset_R_L_I.IDX == idx) 
    {
      offset_R_L_I.S2_Mx(res, dx);
    }
    if(offset_T_L_I.IDX == idx) 
    {
      offset_T_L_I.S2_Mx(res, dx);
    }
    if(vel.IDX == idx) 
    {
      vel.S2_Mx(res, dx);
    }
    if(bg.IDX == idx) 
    {
      bg.S2_Mx(res, dx);
    }
    if(ba.IDX == idx) 
    {
      ba.S2_Mx(res, dx);
    }
    if(grav.IDX == idx) 
    {
      grav.S2_Mx(res, dx);
    }
  }
  friend std::istream& operator>>(std::istream& __is, state_ikfom& __var) 
  {
    //return __is MTK_ISTREAM (vect3, pos)  MTK_ISTREAM (SO3, rot)  MTK_ISTREAM (SO3, offset_R_L_I)  MTK_ISTREAM (vect3, offset_T_L_I)  MTK_ISTREAM (vect3, vel)  MTK_ISTREAM (vect3, bg)  MTK_ISTREAM (vect3, ba)  MTK_ISTREAM (S2, grav)   ;
    return __is >> __var.pos >> __var.rot >> __var.offset_R_L_I >> __var.offset_T_L_I >> __var.vel >> __var.bg >> __var.ba >> __var.grav;
  }
};
Step3:解析 process_noise_ikfom 对应的宏

use-ikfom.hpp 中的如下代码片段为例:

MTK_BUILD_MANIFOLD(process_noise_ikfom,
((vect3, ng))
((vect3, na))
((vect3, nbg))
((vect3, nba))
);

依照上述办法解析.不再赘述.

Step3 的解析结果

对应的代码片段为:

struct process_noise_ikfom 
{
  typedef process_noise_ikfom self;
  std::vector<std::pair<int, int> > S2_state;
  std::vector<std::pair<int, int> > SO3_state;
  std::vector<std::pair<std::pair<int, int>, int> > vect_state;
  //MTK_ENTRIES_OUTPUT_I ( 4, (vect3, ng) , ((vect3, na)) ((vect3, nbg)) ((vect3, nba)) (~), 0, 0, S2_state, SO3_state ) 
  MTK::SubManifold<vect3, 0, 0> ng;
  //MTK_ENTRIES_OUTPUT_I ( 3, (vect3, na) ,  ((vect3, nbg)) ((vect3, nba)) (~), 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, ng)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0 (vect3, ng)::DIM, S2_state, SO3_state) 
  MTK::SubManifold<vect3, 0 + vect3::DOF, 0 + vect3::DIM> na;
  //MTK_ENTRIES_OUTPUT_I ( 2, (vect3, nbg) ,  ((vect3, nba)) (~), 0 + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, na)::DOF, 0 + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, na)::DIM, S2_state, SO3_state) 
  MTK::SubManifold<vect3, 0 + vect3::DOF + vect3::DOF, 0 + vect3::DIM + vect3::DIM> nbg;
  
  //MTK_ENTRIES_OUTPUT_I ( 1, (vect3, nba) ,  (~), 0 + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0 (vect3, nbg)::DOF, 0 + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0 (vect3, nbg)::DIM, S2_state, SO3_state)   
  MTK::SubManifold<vect3, 0 + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + vect3::DIM + vect3::DIM> nba; 
  enum {DOF = vect3::DOF + 0 + vect3::DOF + vect3::DOF + vect3::DOF}; 
  enum {DIM = vect3::DIM+0 + vect3::DIM + vect3::DIM + vect3::DIM}; 
  typedef vect3::scalar scalar;

  //process_noise_ikfom ( BOOST_PP_SEQ_ENUM_4  (const vect3& ng = vect3()) (const vect3& na = vect3()) (const vect3& nbg = vect3()) (const vect3& nba = vect3()) ) : BOOST_PP_SEQ_ENUM_4  (ng(ng)) (na(na)) (nbg(nbg)) (nba(nba)) 
  process_noise_ikfom(const vect3& ng = vect3(), const vect3& na = vect3(), const vect3& nbg = vect3(), const vect3& nba = vect3()) : ng(ng), na(na), nbg(nbg), nba(nba)
  {
  }
  int getDOF() const 
  {
    return DOF;
  }
  void boxplus(const MTK::vectview<const scalar, DOF> & __vec, scalar __scale = 1 ) 
  {
    //MTK_BOXPLUS (vect3, ng)  MTK_BOXPLUS (vect3, na)  MTK_BOXPLUS (vect3, nbg)  MTK_BOXPLUS (vect3, nba)
    ng.boxplus(MTK::subvector(__vec, &self::ng), __scale); 
    na.boxplus(MTK::subvector(__vec, &self::na), __scale); 
    nbg.boxplus(MTK::subvector(__vec, &self::nbg), __scale); 
    nba.boxplus(MTK::subvector(__vec, &self::nba), __scale);
  }
  void oplus(const MTK::vectview<const scalar, DIM> & __vec, scalar __scale = 1 ) 
  {
    //MTK_OPLUS (vect3, ng)  MTK_OPLUS (vect3, na)  MTK_OPLUS (vect3, nbg)  MTK_OPLUS (vect3, nba)
    ng.oplus(MTK::subvector_(__vec, &self::ng), __scale); 
    na.oplus(MTK::subvector_(__vec, &self::na), __scale); 
    nbg.oplus(MTK::subvector_(__vec, &self::nbg), __scale); 
    nba.oplus(MTK::subvector_(__vec, &self::nba), __scale);
  }
  void boxminus(MTK::vectview<scalar,DOF> __res, const process_noise_ikfom& __oth) const 
  {
    //MTK_BOXMINUS (vect3, ng)  MTK_BOXMINUS (vect3, na)  MTK_BOXMINUS (vect3, nbg)  MTK_BOXMINUS (vect3, nba)
    ng.boxminus(MTK::subvector(__res, &self::ng), __oth.ng); 
    na.boxminus(MTK::subvector(__res, &self::na), __oth.na); 
    nbg.boxminus(MTK::subvector(__res, &self::nbg), __oth.nbg); 
    nba.boxminus(MTK::subvector(__res, &self::nba), __oth.nba);
  }
  friend std::ostream& operator<<(std::ostream& __os, const process_noise_ikfom& __var) 
  {
    //return __os MTK_OSTREAM (vect3, ng)  MTK_OSTREAM (vect3, na)  MTK_OSTREAM (vect3, nbg)  MTK_OSTREAM (vect3, nba)   ;
    return __os << __var.ng << " " << __var.na << " " << __var.nbg << " " << __var.nba << " ";
  }
  void build_S2_state() 
  {
    //MTK_S2_state (vect3, ng)  MTK_S2_state (vect3, na)  MTK_S2_state (vect3, nbg)  MTK_S2_state (vect3, nba)
    if(ng.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(ng.IDX, ng.DIM));
    }
    if(na.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(na.IDX, na.DIM));
    }
    if(nbg.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(nbg.IDX, nbg.DIM));
    }
    if(nba.TYP == 1) 
    {
      S2_state.push_back(std::make_pair(nba.IDX, nba.DIM));
    }
  }
  void build_vect_state() 
  {
    //MTK_vect_state (vect3, ng)  MTK_vect_state (vect3, na)  MTK_vect_state (vect3, nbg)  MTK_vect_state (vect3, nba)
    if(ng.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(ng.IDX, ng.DIM), vect3::DOF));
    }
    if(na.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(na.IDX, na.DIM), vect3::DOF));
    }
    if(nbg.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(nbg.IDX, nbg.DIM), vect3::DOF));
    }
    if(nba.TYP == 0) 
    {
      (vect_state).push_back(std::make_pair(std::make_pair(nba.IDX, nba.DIM), vect3::DOF));
    }
  }
  void build_SO3_state() 
  {
    //MTK_SO3_state (vect3, ng)  MTK_SO3_state (vect3, na)  MTK_SO3_state (vect3, nbg)  MTK_SO3_state (vect3, nba)
    if(ng.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(ng.IDX, ng.DIM));
    }
    if(na.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(na.IDX, na.DIM));
    }
    if(nbg.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(nbg.IDX, nbg.DIM));
    }
    if(nba.TYP == 2) 
    {
      (SO3_state).push_back(std::make_pair(nba.IDX, nba.DIM));
    }    
  }
  void S2_hat(Eigen::Matrix<scalar, 3, 3> &res, int idx) 
  {
    //MTK_S2_hat (vect3, ng)  MTK_S2_hat (vect3, na)  MTK_S2_hat (vect3, nbg)  MTK_S2_hat (vect3, nba)
    if(ng.IDX == idx) 
    {
      ng.S2_hat(res);
    }
    if(na.IDX == idx) 
    {
      na.S2_hat(res);
    }
    if(nbg.IDX == idx) 
    {
      nbg.S2_hat(res);
    }
    if(nba.IDX == idx) 
    {
      nba.S2_hat(res);
    }
  }
  void S2_Nx_yy(Eigen::Matrix<scalar, 2, 3> &res, int idx) 
  {
    //MTK_S2_Nx_yy (vect3, ng)  MTK_S2_Nx_yy (vect3, na)  MTK_S2_Nx_yy (vect3, nbg)  MTK_S2_Nx_yy (vect3, nba)
    if(ng.IDX == idx) 
    {
      ng.S2_Nx_yy(res);
    }
    if(na.IDX == idx) 
    {
      na.S2_Nx_yy(res);
    }
    if(nbg.IDX == idx) 
    {
      nbg.S2_Nx_yy(res);
    }
    if(nba.IDX == idx) 
    {
      nba.S2_Nx_yy(res);
    }
  }
  void S2_Mx(Eigen::Matrix<scalar, 3, 2> &res, Eigen::Matrix<scalar, 2, 1> dx, int idx) 
  {
    //MTK_S2_Mx (vect3, ng)  MTK_S2_Mx (vect3, na)  MTK_S2_Mx (vect3, nbg)  MTK_S2_Mx (vect3, nba)
    if(ng.IDX == idx) 
    {
      ng.S2_Mx(res, dx);
    }
    if(na.IDX == idx) 
    {
      na.S2_Mx(res, dx);
    }
    if(nbg.IDX == idx) 
    {
      nbg.S2_Mx(res, dx);
    }
    if(nba.IDX == idx) 
    {
      nba.S2_Mx(res, dx);
    }    
  }
  friend std::istream& operator>>(std::istream& __is, process_noise_ikfom& __var) 
  {
    //return __is MTK_ISTREAM (vect3, ng)  MTK_ISTREAM (vect3, na)  MTK_ISTREAM (vect3, nbg)  MTK_ISTREAM (vect3, nba)   ;
    return __is >> __var.ng >> __var.na >> __var.nbg >> __var.nba;
  }
};
附录:

最终附上解析 三个 宏定义的递归解析代码

input_ikfom 的宏解析代码: input_ikfom_build.hpp

state_ikfom 的宏解析代码: state_ikfom_build.hpp

process_noise_ikfom 的宏解析代码: process_noise_ikfom_build.hpp

工程入口代码: main.cpp

1) input_ikfom_build.hpp
#pragma once

#pragma message(DIS( \
  MTK_BUILD_MANIFOLD(input_ikfom,  \
  ((vect3, acc))  \
  ((vect3, gyro))  \
  )  \
))
#pragma message(DIS( \
  MTK_ENTRIES_OUTPUT_I ( 2, (vect3, acc) , ((vect3, gyro)) (~), 0, 0, S2_state, SO3_state )  \
))
#pragma message(DIS( \
  MTK_PUT_TYPE(vect3, acc, 0, 0, S2_state, SO3_state) \
))
#pragma message(DIS( \
  MTK_ENTRIES_OUTPUT_I(1, (vect3, gyro), (~), 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, acc)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, acc)::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
  MTK_PUT_TYPE_AND_ENUM ( vect3, gyro, 0 + vect3::DOF, 0 + vect3::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
 input_ikfom(BOOST_PP_SEQ_ENUM_2(const vect3& acc = vect3()) (const vect3& gyro = vect3())) : BOOST_PP_SEQ_ENUM_2(acc(acc)) (gyro(gyro)) { } \
))
#pragma message(DIS( \
  MTK_BOXPLUS(vect3, acc)  MTK_BOXPLUS(vect3, gyro)  \
))
#pragma message(DIS( \
  MTK_OPLUS(vect3, acc)  MTK_OPLUS(vect3, gyro) \
))
#pragma message(DIS( \
 MTK_BOXMINUS(vect3, acc)  MTK_BOXMINUS(vect3, gyro) \
))
#pragma message(DIS( \
  return __os MTK_OSTREAM(vect3, acc)  MTK_OSTREAM(vect3, gyro); \
))
#pragma message(DIS( \
  MTK_S2_state(vect3, acc)  MTK_S2_state(vect3, gyro) \
))
#pragma message(DIS( \
  MTK_vect_state(vect3, acc)  MTK_vect_state(vect3, gyro) \
))
#pragma message(DIS( \
  MTK_SO3_state(vect3, acc)  MTK_SO3_state(vect3, gyro) \
))
#pragma message(DIS( \
  MTK_S2_hat(vect3, acc)  MTK_S2_hat(vect3, gyro) \
))
#pragma message(DIS( \
  MTK_S2_Nx_yy(vect3, acc)  MTK_S2_Nx_yy(vect3, gyro) \
))
#pragma message(DIS( \
  MTK_S2_Mx(vect3, acc)  MTK_S2_Mx(vect3, gyro) \
))
#pragma message(DIS( \
  return __is MTK_ISTREAM(vect3, acc)  MTK_ISTREAM(vect3, gyro); \
))
2) state_ikfom_build.hpp
#pragma once

#pragma message(DIS( \
	MTK_BUILD_MANIFOLD(state_ikfom, \
	((vect3, pos))   \
	((SO3, rot))  \
	((SO3, offset_R_L_I))  \
	((vect3, offset_T_L_I))		\
	((vect3, vel))	\
	((vect3, bg))	\
	((vect3, ba))	\
	((S2, grav))	\
	);	\
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(8, (vect3, pos), ((SO3, rot)) ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0, 0, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE ( vect3, pos, 0, 0, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(7, (SO3, rot), ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, pos)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, pos)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I(6, (SO3, offset_R_L_I), ((vect3, offset_T_L_I)) ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(SO3, rot)::DOF, 0 + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(SO3, rot)::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE(SO3, rot, 0 + vect3::DOF, 0 + vect3::DIM, S2_state, SO3_state) MTK_PUT_TYPE(SO3, offset_R_L_I, 0 + vect3::DOF + SO3::DOF, 0 + vect3::DIM + SO3::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(5, (vect3, offset_T_L_I), ((vect3, vel)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + BOOST_PP_TUPLE_ELEM_2_0(SO3, offset_R_L_I)::DOF, 0 + vect3::DIM + SO3::DIM + BOOST_PP_TUPLE_ELEM_2_0(SO3, offset_R_L_I)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I(4, (vect3, vel), ((vect3, bg)) ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, offset_T_L_I)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, offset_T_L_I)::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   MTK_PUT_TYPE(vect3, offset_T_L_I, 0 + vect3::DOF + SO3::DOF + SO3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM, S2_state, SO3_state) MTK_PUT_TYPE(vect3, vel, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(3, (vect3, bg), ((vect3, ba)) ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, vel)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, vel)::DIM, S2_state, SO3_state) MTK_ENTRIES_OUTPUT_I(2, (vect3, ba), ((S2, grav)) (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, bg)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, bg)::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE(vect3, bg, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM, S2_state, SO3_state) MTK_PUT_TYPE(vect3, ba, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(1, (S2, grav), (~), 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, ba)::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, ba)::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   MTK_PUT_TYPE_AND_ENUM(S2, grav, 0 + vect3::DOF + SO3::DOF + SO3::DOF + vect3::DOF + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + SO3::DIM + SO3::DIM + vect3::DIM + vect3::DIM + vect3::DIM + vect3::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   state_ikfom(BOOST_PP_SEQ_ENUM_8(const vect3& pos = vect3()) (const SO3& rot = SO3()) (const SO3& offset_R_L_I = SO3()) (const vect3& offset_T_L_I = vect3()) (const vect3& vel = vect3()) (const vect3& bg = vect3()) (const vect3& ba = vect3()) (const S2& grav = S2())) : BOOST_PP_SEQ_ENUM_8(pos(pos)) (rot(rot)) (offset_R_L_I(offset_R_L_I)) (offset_T_L_I(offset_T_L_I)) (vel(vel)) (bg(bg)) (ba(ba)) (grav(grav)) \
))
#pragma message(DIS( \
   MTK_BOXPLUS(vect3, pos)  MTK_BOXPLUS(SO3, rot)  MTK_BOXPLUS(SO3, offset_R_L_I)  MTK_BOXPLUS(vect3, offset_T_L_I)  MTK_BOXPLUS(vect3, vel)  MTK_BOXPLUS(vect3, bg)  MTK_BOXPLUS(vect3, ba)  MTK_BOXPLUS(S2, grav)  \
))
#pragma message(DIS( \
   MTK_OPLUS(vect3, pos)  MTK_OPLUS(SO3, rot)  MTK_OPLUS(SO3, offset_R_L_I)  MTK_OPLUS(vect3, offset_T_L_I)  MTK_OPLUS(vect3, vel)  MTK_OPLUS(vect3, bg)  MTK_OPLUS(vect3, ba)  MTK_OPLUS(S2, grav) \
))
#pragma message(DIS( \
   MTK_BOXMINUS(vect3, pos)  MTK_BOXMINUS(SO3, rot)  MTK_BOXMINUS(SO3, offset_R_L_I)  MTK_BOXMINUS(vect3, offset_T_L_I)  MTK_BOXMINUS(vect3, vel)  MTK_BOXMINUS(vect3, bg)  MTK_BOXMINUS(vect3, ba)  MTK_BOXMINUS(S2, grav)  \
### ))
#pragma message(DIS( \
   return __os MTK_OSTREAM(vect3, pos)  MTK_OSTREAM(SO3, rot)  MTK_OSTREAM(SO3, offset_R_L_I)  MTK_OSTREAM(vect3, offset_T_L_I)  MTK_OSTREAM(vect3, vel)  MTK_OSTREAM(vect3, bg)  MTK_OSTREAM(vect3, ba)  MTK_OSTREAM(S2, grav); \
))
#pragma message(DIS( \
   MTK_S2_state(vect3, pos)  MTK_S2_state(SO3, rot)  MTK_S2_state(SO3, offset_R_L_I)  MTK_S2_state(vect3, offset_T_L_I)  MTK_S2_state(vect3, vel)  MTK_S2_state(vect3, bg)  MTK_S2_state(vect3, ba)  MTK_S2_state(S2, grav) \
))
#pragma message(DIS( \
   MTK_vect_state(vect3, pos)  MTK_vect_state(SO3, rot)  MTK_vect_state(SO3, offset_R_L_I)  MTK_vect_state(vect3, offset_T_L_I)  MTK_vect_state(vect3, vel)  MTK_vect_state(vect3, bg)  MTK_vect_state(vect3, ba)  MTK_vect_state(S2, grav)  \
))
#pragma message(DIS( \
   MTK_SO3_state(vect3, pos)  MTK_SO3_state(SO3, rot)  MTK_SO3_state(SO3, offset_R_L_I)  MTK_SO3_state(vect3, offset_T_L_I)  MTK_SO3_state(vect3, vel)  MTK_SO3_state(vect3, bg)  MTK_SO3_state(vect3, ba)  MTK_SO3_state(S2, grav) \
))
#pragma message(DIS( \
   MTK_S2_hat(vect3, pos)  MTK_S2_hat(SO3, rot)  MTK_S2_hat(SO3, offset_R_L_I)  MTK_S2_hat(vect3, offset_T_L_I)  MTK_S2_hat(vect3, vel)  MTK_S2_hat(vect3, bg)  MTK_S2_hat(vect3, ba)  MTK_S2_hat(S2, grav) \
))
#pragma message(DIS( \
   MTK_S2_Nx_yy(vect3, pos)  MTK_S2_Nx_yy(SO3, rot)  MTK_S2_Nx_yy(SO3, offset_R_L_I)  MTK_S2_Nx_yy(vect3, offset_T_L_I)  MTK_S2_Nx_yy(vect3, vel)  MTK_S2_Nx_yy(vect3, bg)  MTK_S2_Nx_yy(vect3, ba)  MTK_S2_Nx_yy(S2, grav) \
))
#pragma message(DIS( \
   MTK_S2_Mx(vect3, pos)  MTK_S2_Mx(SO3, rot)  MTK_S2_Mx(SO3, offset_R_L_I)  MTK_S2_Mx(vect3, offset_T_L_I)  MTK_S2_Mx(vect3, vel)  MTK_S2_Mx(vect3, bg)  MTK_S2_Mx(vect3, ba)  MTK_S2_Mx(S2, grav) \
))
#pragma message(DIS( \
   return __is MTK_ISTREAM(vect3, pos)  MTK_ISTREAM(SO3, rot)  MTK_ISTREAM(SO3, offset_R_L_I)  MTK_ISTREAM(vect3, offset_T_L_I)  MTK_ISTREAM(vect3, vel)  MTK_ISTREAM(vect3, bg)  MTK_ISTREAM(vect3, ba)  MTK_ISTREAM(S2, grav); \
))
3) process_noise_ikfom_build.hpp
#pragma once

#pragma message(DIS( \
	MTK_BUILD_MANIFOLD(process_noise_ikfom,  \
	((vect3, ng))  \
	((vect3, na))  \
	((vect3, nbg))  \
	((vect3, nba))  \
	);  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I ( 4, (vect3, ng) , ((vect3, na)) ((vect3, nbg)) ((vect3, nba)) (~), 0, 0, S2_state, SO3_state )   \
))
#pragma message(DIS( \
   MTK_PUT_TYPE ( vect3, ng, 0, 0, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(3, (vect3, na), ((vect3, nbg)) ((vect3, nba)) (~), 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, ng)::DOF, 0 + BOOST_PP_TUPLE_ELEM_2_0(vect3, ng)::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE(vect3, na, 0 + vect3::DOF, 0 + vect3::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(2, (vect3, nbg), ((vect3, nba)) (~), 0 + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, na)::DOF, 0 + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, na)::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE(vect3, nbg, 0 + vect3::DOF + vect3::DOF, 0 + vect3::DIM + vect3::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_ENTRIES_OUTPUT_I(1, (vect3, nba), (~), 0 + vect3::DOF + vect3::DOF + BOOST_PP_TUPLE_ELEM_2_0(vect3, nbg)::DOF, 0 + vect3::DIM + vect3::DIM + BOOST_PP_TUPLE_ELEM_2_0(vect3, nbg)::DIM, S2_state, SO3_state)  \
))
#pragma message(DIS( \
   MTK_PUT_TYPE_AND_ENUM(vect3, nba, 0 + vect3::DOF + vect3::DOF + vect3::DOF, 0 + vect3::DIM + vect3::DIM + vect3::DIM, S2_state, SO3_state) \
))
#pragma message(DIS( \
   process_noise_ikfom(BOOST_PP_SEQ_ENUM_4(const vect3& ng = vect3()) (const vect3& na = vect3()) (const vect3& nbg = vect3()) (const vect3& nba = vect3())) : BOOST_PP_SEQ_ENUM_4(ng(ng)) (na(na)) (nbg(nbg)) (nba(nba))  \
))
#pragma message(DIS( \
   MTK_BOXPLUS(vect3, ng)  MTK_BOXPLUS(vect3, na)  MTK_BOXPLUS(vect3, nbg)  MTK_BOXPLUS(vect3, nba) \
))
#pragma message(DIS( \
   MTK_OPLUS(vect3, ng)  MTK_OPLUS(vect3, na)  MTK_OPLUS(vect3, nbg)  MTK_OPLUS(vect3, nba) \
))
#pragma message(DIS( \
   MTK_BOXMINUS(vect3, ng)  MTK_BOXMINUS(vect3, na)  MTK_BOXMINUS(vect3, nbg)  MTK_BOXMINUS(vect3, nba) \
))
#pragma message(DIS( \
   return __os MTK_OSTREAM(vect3, ng)  MTK_OSTREAM(vect3, na)  MTK_OSTREAM(vect3, nbg)  MTK_OSTREAM(vect3, nba); \
))
#pragma message(DIS( \
   MTK_S2_state(vect3, ng)  MTK_S2_state(vect3, na)  MTK_S2_state(vect3, nbg)  MTK_S2_state(vect3, nba) \
))
#pragma message(DIS( \
   MTK_vect_state(vect3, ng)  MTK_vect_state(vect3, na)  MTK_vect_state(vect3, nbg)  MTK_vect_state(vect3, nba) \
))
#pragma message(DIS( \
   MTK_SO3_state(vect3, ng)  MTK_SO3_state(vect3, na)  MTK_SO3_state(vect3, nbg)  MTK_SO3_state(vect3, nba) \
))
#pragma message(DIS( \
   MTK_S2_hat(vect3, ng)  MTK_S2_hat(vect3, na)  MTK_S2_hat(vect3, nbg)  MTK_S2_hat(vect3, nba) \
))
#pragma message(DIS( \
   MTK_S2_Nx_yy(vect3, ng)  MTK_S2_Nx_yy(vect3, na)  MTK_S2_Nx_yy(vect3, nbg)  MTK_S2_Nx_yy(vect3, nba) \
))
#pragma message(DIS( \
   MTK_S2_Mx(vect3, ng)  MTK_S2_Mx(vect3, na)  MTK_S2_Mx(vect3, nbg)  MTK_S2_Mx(vect3, nba) \
))
#pragma message(DIS( \
   return __is MTK_ISTREAM(vect3, ng)  MTK_ISTREAM(vect3, na)  MTK_ISTREAM(vect3, nbg)  MTK_ISTREAM(vect3, nba); \
))
4) main.cpp
#include <iostream>
#include "use-ikfom.hpp"

// 定义用于显示宏内容的宏
#define M(x) #x
#define DIS(x) #x"=>\n\t"M(x)

#include "input_ikfom_build.hpp"
#include "state_ikfom_build.hpp"
#include "process_noise_ikfom_build.hpp"

int main()
{
    return 0;
}