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.