在 C 中定义指令不明确

Ambiguous Define Directive in C

本文关键字:指令 不明确 定义      更新时间:2023-10-16

我正在查看一些代码(PCL(,发现这个定义指令:

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

有人可以向我解释这是在做什么(并可能提供此功能的参考吗?这样的东西什么时候有用?

哦,天哪,这搞砸了。

短版本

它是预处理器的类似列表的结构(Boost PP 术语中的"序列"(,由 Boost 预处理器宏(=black magic(使用;所有PCL_*_POINT_TYPES宏都将与 PCL_INSTANTIATE 宏一起使用,以(通过复杂的方式(为序列中给定的类型提供一些模板的显式实例化。

长版本

免责声明:我对PCL没有任何具体的专业知识,我只是喋喋不休;所有对代码的引用都是相对于PCL SVN r8781的。

它似乎是这样工作的:

  • 所有PCL_*_POINT_TYPES都是旨在与PCL_INSTANTIATE宏一起使用的宏;

    #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使用 BOOST_PP_CATPCL_INSTANTIATE_PCL_INSTANTIATETEMPLATE参数连接起来,并将点类型(即从PCL_*_POINT_TYPES宏列表中提取的点类型(粘在它后面的括号中。

所以,在写作时

PCL_INSTANTIATE(Search, PCL_POINT_TYPES)

(摘自此处,第 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 的参数(又是其他宏,在其他地方定义。此类宏通常扩展到显式模板实例化:

#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,这件事的全部意义在于提供一个简洁的方法来显式实例化所有指定类型的模板类。我没有进一步看,但我想这样做是为了避免在使用库的代码中需要"正常"("现场"(模板扩展,也许是为了加快编译时间,将可能的模板扩展限制为那些确定的类型,将它们保存在共享库中(以降低客户端可执行文件的大小(, 或者为了一些甚至不同的东西。