C语言中的歧义定义指令 [英] Ambiguous Define Directive in C

查看:119
本文介绍了C语言中的歧义定义指令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在浏览一些代码(PCL),发现了这个define指令:

#define PCL_FEATURE_POINT_TYPES \
  (pcl::PFHSignature125)        \
  (pcl::PFHRGBSignature250)     \
  (pcl::PPFSignature)           \
  (pcl::PPFRGBSignature)        \
  (pcl::NormalBasedSignature12) \
  (pcl::FPFHSignature33)        \
  (pcl::VFHSignature308)        \
  (pcl::Narf36)

有人可以向我解释这是做什么的(并可能提供对此功能的引用吗?).什么时候这样有用?

解决方案

天哪,这很糟.

简短版

这是一个类似列表的结构( (在Boost PP措辞中). rel ="nofollow">提升预处理器宏(=黑魔法);所有PCL_*_POINT_TYPES宏都将与PCL_INSTANTIATE宏一起使用(通过卷积方法)提供序列中给定类型的某些模板的显式实例.

长版

免责声明:我没有关于PCL的任何专门知识,只是四处游荡.所有对该代码的引用都是相对于PCL SVN r8781的.

它看起来像这样工作:

  • 所有PCL_*_POINT_TYPES是旨在与 PCL_INSTANTIATE <一起使用的宏/a>宏;

    #define PCL_INSTANTIATE (TEMPLATE, POINT_TYPES) BOOST_PP_SEQ_FOR_EACH(PCL_INSTANTIATE_IMPL, TEMPLATE, POINT_TYPES)
    

  • 此宏使用Boost宏 BOOST_PP_SEQ_FOR_EACH 从该序列" ,并将其输入到PCL_INSTANTIATE_IMPL:

    #define PCL_INSTANTIATE_IMPL (r, TEMPLATE, POINT_TYPE) BOOST_PP_CAT(PCL_INSTANTIATE_, TEMPLATE)(POINT_TYPE)
    

  • PCL_INSTANTIATE_IMPL依次使用此处,第43行)

    实际发生的是

    PCL_INSTANTIATE_Search(pcl::PointXYZRGBA) PCL_INSTANTIATE_Search(pcl::PointXYZRGB) PCL_INSTANTIATE_Search(pcl::PointXYZRGBL) PCL_INSTANTIATE_Search(pcl::PointXYZRGBNormal) PCL_INSTANTIATE_Search(pcl::PointSurfel)
    

    现在,PCL_INSTANTIATE_Search(及其所有同级元素PCL_INSTANTIATE_T,其中T是PCL_INSTANTIATE的自变量)依次是在其他位置定义的 other 宏.这样的宏通常会扩展为显式的模板实例化:

    #define PCL_INSTANTIATE_Search(T) template class PCL_EXPORTS pcl::search::Search<T>;
    

    (来自此处,第208行;请注意宏末尾的分号)

    最后,它变成:

    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBA>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGB>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBL>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBNormal>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointSurfel>;
    

    (添加了换行符)

    因此,整个过程归结为一系列显式的模板实例化.


    再次总结一下:PCL_*_POINT_TYPES是要与PCL_INSTANTIATE一起使用的类型的预处理器列表"; PCL_INSTANTIATE获取列表,并使用奇怪的魔法将列表中所有类型的模板相对于指定后缀(例如Search)实例化.

    因此,AFAICT的全部目的是提供一种简洁的方法,以在所有指定的类型上显式实例化模板类.我没有进一步看,但是我想这样做是为了避免在使用该库的代码中进行常规"(当场")模板扩展的需要,也许是为了加快编译时间,以限制可能的使用时间.模板仅扩展为那些确定的类型,以将它们保留在共享库中(以减小客户端可执行文件的大小),甚至扩展为其他类型.

    I was looking through some code (PCL) and found this define directive:

    #define PCL_FEATURE_POINT_TYPES \
      (pcl::PFHSignature125)        \
      (pcl::PFHRGBSignature250)     \
      (pcl::PPFSignature)           \
      (pcl::PPFRGBSignature)        \
      (pcl::NormalBasedSignature12) \
      (pcl::FPFHSignature33)        \
      (pcl::VFHSignature308)        \
      (pcl::Narf36)
    

    Can someone explain to me what this is doing (and possibly provide a reference to this feature?). When would something like this be useful?

    解决方案

    Oh boy, this is messed up.

    Short version

    It's a list-like structure (a "sequence" in Boost PP parlance) for the preprocessor, used by the Boost Preprocessor Macros (=black magic); all the PCL_*_POINT_TYPES macros are to be used with the PCL_INSTANTIATE macro to provide (via convoluted means) explicit instantiations of some templates for the types given in the sequence.

    Long version

    Disclaimer: I don't have any specific expertise about PCL, I just grepped around a lot; all references to the code are relative to PCL SVN r8781.

    It seems to work like this:

    • all the PCL_*_POINT_TYPES are macros intended to be used with the PCL_INSTANTIATE macro;

      #define PCL_INSTANTIATE (TEMPLATE, POINT_TYPES) BOOST_PP_SEQ_FOR_EACH(PCL_INSTANTIATE_IMPL, TEMPLATE, POINT_TYPES)
      

    • this macro uses the Boost macro BOOST_PP_SEQ_FOR_EACH to extract each element from that "sequence", and feed it to PCL_INSTANTIATE_IMPL:

      #define PCL_INSTANTIATE_IMPL (r, TEMPLATE, POINT_TYPE) BOOST_PP_CAT(PCL_INSTANTIATE_, TEMPLATE)(POINT_TYPE)
      

    • PCL_INSTANTIATE_IMPL, in turn, uses BOOST_PP_CAT to concatenate PCL_INSTANTIATE_ with the TEMPLATE parameter of PCL_INSTANTIATE. and sticks the point type (i.e. the one extracted from the list of the PCL_*_POINT_TYPES macro) after it, in parentheses.

    So, when writing

    PCL_INSTANTIATE(Search, PCL_POINT_TYPES)
    

    (taken from here, line 43)

    what actually happens is

    PCL_INSTANTIATE_Search(pcl::PointXYZRGBA) PCL_INSTANTIATE_Search(pcl::PointXYZRGB) PCL_INSTANTIATE_Search(pcl::PointXYZRGBL) PCL_INSTANTIATE_Search(pcl::PointXYZRGBNormal) PCL_INSTANTIATE_Search(pcl::PointSurfel)
    

    Now, PCL_INSTANTIATE_Search (and all its siblings PCL_INSTANTIATE_T where T is the argument to PCL_INSTANTIATE) are in turn other macros, defined elsewhere. Such macros typically expand to explicit template instantiations:

    #define PCL_INSTANTIATE_Search(T) template class PCL_EXPORTS pcl::search::Search<T>;
    

    (from here, line 208; notice the semicolon at the end of the macro)

    In the end, it becomes:

    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBA>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGB>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBL>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointXYZRGBNormal>;
    template class PCL_EXPORTS pcl::search::Search<pcl::PointSurfel>;
    

    (newlines added)

    Thus, the whole thing boils down to a series of explicit template instantiations.


    To sum up again: PCL_*_POINT_TYPES is a "preprocessor list" of types to be used with PCL_INSTANTIATE; PCL_INSTANTIATE takes the list, and, with strange sorceries, instantiates the template relative to the specified suffix (e.g. Search in this case) for all the types in the list.

    So, AFAICT, the whole point of this thing is to provide a concise mean to explicitly instantiate a template class over all the specified types. I didn't look further, but I suppose that this is done to avoid the need of "normal" ("on the spot") templates expansions in the code that uses the library, maybe to speed up compilation times, to limit the possible templates expansions only to those definite types, to keep them in a shared library (to keep down the client executable size), or for something even different.

    这篇关于C语言中的歧义定义指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆