Consider the following header file:
// Foo.h
class Foo {
public:
template
void read(T& value);
};
I
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"
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*);
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.
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
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 >;