Consider the following header file:
// Foo.h
class Foo {
public:
template <typename T>
void read(T& value);
};
I want to explicitly instantiate the Foo::read
member function template in a source file for all types included in a boost::mpl::vector
:
// Foo.cc
#include <boost/mpl/vector.hpp>
#include <boost/mpl/begin_end.hpp>
#include "Foo.h"
template <typename T>
void Foo::read(T& value) { /* do something */ }
typedef boost::mpl::vector<int, long, float> types;
// template Foo::read<int >(int&);
// template Foo::read<long >(long&);
// template Foo::read<float>(float&);
// instantiate automatically ???
Is it possible? Thanks in advance, Daniel.
EDIT
I found some solution - it seems that assigning a pointer to Foo::read<T>
in the constructor of a struct, of which variable is then declared, cause instantiation:
// intermezzo
template <typename T> struct Bar {
Bar<T>() {
void (Foo::*funPtr)(T&) = &Foo::read<T>;
}
};
static Bar<int > bar1;
static Bar<long > bar2;
static Bar<float> bar3;
So then the process can be automatized as follows:
// Foo.cc continued
template <typename B, typename E>
struct my_for_each {
my_for_each<B, E>() {
typedef typename B::type T; // vector member
typedef void (Foo::*FunPtr)(T&); // pointer to Foo member function
FunPtr funPtr = &Foo::read<T>; // cause instantiation?
}
my_for_each<typename boost::mpl::next<B>::type, E> next;
};
template<typename E>
struct my_for_each<E, E> {};
static my_for_each< boost::mpl::begin<types>::type,
boost::mpl::end<types>::type > first;
But I don't know if this solution is portable and standard-conformant? (Works with Intel and GNU compilers.)
I've had the same requirement not long ago, and had good results with a simple function template instantiation:
template <class... T>
void forceInstantiation(typedef boost::mpl::vector<T...>*) {
using ex = int[];
(void)ex{(void(&Foo::read<T>), 0)..., 0};
// C++17
// (void)((void(&Foo::read<T>), ...));
}
template void forceInstantiation(types*);
I am not sure if this is the solution to your problem, but maybe you can do with a template specialization.
New header:
// Foo.h
template < typename T >
struct RealRead;
class Foo {
public:
template <typename T>
void read(T& value);
};
template <typename T>
void Foo::read(T& value)
{
RealRead< T >::read( value );
}
New source :
template < >
struct RealRead< int >
{
static void read( int & v )
{
// do read
}
};
template < >
struct RealRead< float >
{
static void read( float & v )
{
// do read
}
};
//etc
// explicitly instantiate templates
template struct RealRead< int >;
template struct RealRead< float >;
You can explicitly instantiate Foo for a given T template parameter with template class Foo<T>;
As for batch instantiation, I don't think it is possible. Maybe with variadic templates it is possible to create an Instantiate class so something like Instantiate<Foo, int, short, long, float, etc>
would instantiate the appropriate templates, but other than that, you have to resort to manual instantiation.
explicit instantiation has special grammar and special meaning to complier, so cannot be done with meta programming.
your solution cause a instantiation, but not a explicit instantiation.
I don't think it is necessary, nor is it possible.
You can directly use (call) the function Foo:read(bar), for variable bar of any type, as long as the type is well-defined in your template function implementation. The compiler will automatically morph your argument into type "T".
For example:
template <class T>
Foo::read(T & var)
{
std::cin >> var;
}
T is well-defined when T is a streaming type supported by cin.
The example will be self-contained, if "Foo::" is removed. I mean, for "Foo::", you should have somewhere defined a class Foo, or a namespace Foo, to make it work.
Yet please note that template should always go inside a .h file, not a .cpp file (just search the web with keyword "c++ template can not be implemented in cpp file"
If you intend to use your class only in a single module (i.e. you won't export it) you can use boost/mpl/for_each. The template function defined this way (using mpl/for_each) won't be exported (even if you declare __declspec(export) before class name or function signature):
// Foo.cpp
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
template<class T>
void read(T& value)
{
...
}
using types = boost::mpl::vector<long, int>;
//template instantiation
struct call_read {
template <class T>
void operator()(T)
{
T t; //You should make sure that T can be created this way
((Foo*)nullptr)->read<T>(t); //this line tells to compiler with templates it should instantiate
}
};
void instantiate()
{
boost::mpl::for_each<types>(call_read());
}
If you need export/import you structure and template methods there is the solution using boost/preprocessor
// Foo.h
#ifdef <preprocessor definition specific to DLL>
# define API __declspec(dllexport)
#else
# define API __declspec(dllimport)
#endif
class API Foo {
public:
template<class T> void read(T& value);
};
// Foo.cpp
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/mpl/vector.hpp>
template<class T>
void read(T& value)
{
...
}
//using this macro you can define both boost::mpl structure AND instantiate explicitly your template function
#define VARIANT_LIST (std::wstring)(long)(int)
using types = boost::mpl::vector<BOOST_PP_SEQ_ENUM(VARIANT_LIST)>;
//Here we should use our API macro
#define EXPLICIT_INSTANTIATION(r, d, __type__) \
template API void Foo::read<__type__>(__type__&);
BOOST_PP_SEQ_FOR_EACH(EXPLICIT_INSTANTIATION, _, VARIANT_LIST)
If you don't need this extra functionality the first solution is much cleaner I guess
来源:https://stackoverflow.com/questions/5715586/how-to-explicitly-instantiate-a-template-for-all-members-of-mpl-vector-in-c