Как явно создать экземпляр шаблона для всех членов вектора MPL в C ++? - PullRequest
20 голосов
/ 19 апреля 2011

Рассмотрим следующий заголовочный файл:

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

Я хочу явно создать экземпляр шаблона функции-члена Foo::read в исходном файле для всех типов, включенных в 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 ???

Возможно ли это?Спасибо заранее, Даниэль.

РЕДАКТИРОВАТЬ

Я нашел какое-то решение - кажется, что присвоение указателя на Foo::read<T> в конструкторе структуры, переменная которойзатем объявляется, вызывает создание экземпляров:

// 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;

Итак, процесс может быть автоматизирован следующим образом:

// 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;

Но я не знаю, является ли это решение переносимым и совместимым со стандартами?(Работает с компиляторами Intel и GNU.)

Ответы [ 6 ]

1 голос
/ 31 декабря 2016

Недавно у меня было такое же требование, и у меня были хорошие результаты при простой реализации шаблона функции:

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 голосов
/ 09 марта 2016

Если вы намереваетесь использовать свой класс только в одном модуле (т.е. вы не будете его экспортировать), вы можете использовать boost / mpl / for_each.Функция шаблона, определенная таким образом (с использованием mpl / for_each), не будет экспортирована (даже если вы объявите __declspec (экспорт) перед именем класса или сигнатурой функции):

// 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());
}

Если вам нужен экспорт / импорт,методы структуры и шаблонов есть решение с использованием 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)

Если вам не нужны эти дополнительные функции, первое решение намного чище, я думаю

0 голосов
/ 04 сентября 2014

Я не думаю, что это необходимо, и это невозможно.

Вы можете напрямую использовать (вызывать) функцию Foo: read (bar) для переменной bar любого типа, если толькоТип четко определен в вашей реализации функции шаблона.Компилятор автоматически преобразует ваш аргумент в тип "T".

Например:

template <class T>
Foo::read(T & var)
{
    std::cin >> var;
}

T хорошо определен, когда T является типом потоковой передачи, поддерживаемым cin.

Пример будет автономным, если удалить «Foo ::».Я имею в виду, что для "Foo ::" вы должны были где-то определить класс Foo или пространство имен Foo, чтобы он работал.

Тем не менее, обратите внимание, что шаблон всегда должен идти внутри файла .h, а нефайл .cpp (просто поиск в Интернете по ключевому слову "шаблон c ++ не может быть реализован в файле cpp"

0 голосов
/ 23 мая 2014

явное создание экземпляров имеет специальную грамматику и особое значение для компилятора, поэтому не может быть сделано с метапрограммированием.

ваше решение вызывает создание экземпляра, но не явное создание.

0 голосов
/ 01 июля 2011

Вы можете явно создать экземпляр Foo для заданного параметра шаблона T с помощью template class Foo<T>;

Что касается пакетной реализации, я не думаю, что это возможно. Возможно, с помощью шаблонов с переменным числом элементов можно создать класс Instantiate, чтобы что-то вроде Instantiate<Foo, int, short, long, float, etc> создавало бы соответствующие шаблоны, но в остальном вам придется прибегнуть к ручному созданию экземпляров.

0 голосов
/ 19 апреля 2011

Я не уверен, что это решение вашей проблемы, но, возможно, вы можете сделать это со специализацией шаблона.

Новый заголовок:

// 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 );
}

Новый источник:

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 >;
...