How to explicitly instantiate a template for all members of MPL vector in C++?

匆匆过客 提交于 2019-12-02 18:14:14

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!