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

后端 未结 6 567
日久生厌
日久生厌 2021-02-01 05:53

Consider the following header file:

// Foo.h
class Foo {
    public: 
        template 
        void read(T& value);
};

I

相关标签:
6条回答
  • 2021-02-01 06:21

    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"

    0 讨论(0)
  • 2021-02-01 06:22

    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*);
    
    0 讨论(0)
  • 2021-02-01 06:27

    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.

    0 讨论(0)
  • 2021-02-01 06:31

    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.

    0 讨论(0)
  • 2021-02-01 06:32

    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

    0 讨论(0)
  • 2021-02-01 06:33

    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 >;
    
    0 讨论(0)
提交回复
热议问题