Meaning of the following template function?

105 views Asked by At
#define Create_Function(Type) \
    template void Function( std::vector<boost::shared_ptr<Type>>&)

Create_Function(std::string);

I have seen the above code in legacy code but have no idea what the meaning of it. It is neither a regular non-specialized function definition nor a full specialized function definition.

Any idea?

2

There are 2 answers

6
TemplateRex On BEST ANSWER

It does explicit template instantiation (see MSDN)

Explicit instantiation lets you create an instantiation of a templated class or function without actually using it in your code. Because this is useful when you are creating library (.lib) files that use templates for distribution, uninstantiated template definitions are not put into object (.obj) files.

Given a general function template

template<typename T>
void Function( std::vector<boost::shared_ptr<T>>&)
{
    // bla bla
}

The call to the macro Create_Function(std::string); will expand to

template void Function( std::vector<boost::shared_ptr<std::string>>&);
4
David Rodríguez - dribeas On

That is an explicit instantiation of a function template. Given a template like:

template <typename T>
void Function( std::vector<boost::shared_ptr<T> >& );

(probably declared in a header and defined in a .cpp file), the code:

template void Function( std::vector<boost::shared_ptr<int> >& );

requires that the compiler instantiates (generates code for) the specialization in this translation unit. This can be used to reduce compile times, as users of the template would only need to see the declaration of the template and won't instantiate it in each translation unit where it is used. On the down side, it requires that for each type used with that template, the explicit instantiation is performed in a translation unit that has access to the definition of the template, which limits the use of the template to those instantiations.

// tmpl.h
template <typename T>
void Function( std::vector<boost::shared_ptr<T> >& );

// tmpl.cpp
template <typename T>
void Function( std::vector<boost::shared_ptr<T> >& p ) {
    ... 
}
template void Function( std::vector<boost::shared_ptr<int> >& );
template void Function( std::vector<boost::shared_ptr<double> >& );

// user.cpp, user2.cpp, user3.cpp
#include <tmpl.h>
...
    std::vector<boost::shared_ptr<int> > v;
    Function( v );                             // [1]

In this example, when compiling 'user#.cpp' we don't incur the cost of instantiation of the Function template in all translation units that odr-use it, only in 'tmpl.cpp', potentially reducing the compilation time.

Sometimes the down side is actually the reason for this approach, as you can effectively limit the instantiating types to the subset for which you have provided the explicit instantiation (i.e. in the code above, if 'userN.cpp' tried to call Function passing a vector of shared pointers to std::string the linker will complain).

Finally, in a few cases I have seen it as a way of hiding the actual implementation of the template from users of a library when the set of types for which it can be used is limited.