Ambiguous Define Directive in C

2019-05-14 20:42发布

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?

1条回答
Viruses.
2楼-- · 2019-05-14 21:27

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.

查看更多
登录 后发表回答