Intereting Posts
повысить статус действительности iteratorа multi_index после стирания во внутреннем цикле Иногда возникает segmentation fault, когда функция cvCreateFileCapture вызывается по сетевому URL-адресу Варианты для разработки classов с использованием безопасного downcasting Является ли sizeof (int ()) законным выражением? C ++ Variadic template AND и OR Минимальный набор вложенных typedef для пользовательской последовательности STL? что означает «OLE» Приложение называется интерфейсом, который был настроен для другого streamа »после вызова RevokeDragDrop? Новое ключевое слово «авто»; Когда он должен использоваться для объявления типа переменной? Чтение и запись файла в массив std :: thread: как объявить stream в classе как обычный член? Значение по умолчанию для указателя функции в C ++ Объявление вперед включает, помимо объявления include (ClassFwd.h + Class.h) AWS C ++ S3 SDK PutObjectRequest не может подключиться к конечной точке Доступ к переменной на C ++ путем «сшивания» ее имени вместе неопределенная ссылка с разделяемой библиотекой с использованием cmake

Укажите параметры шаблона во время выполнения

Рассмотрим следующий шаблонный class

class MyClassInterface { public: virtual double foo(double) = 0; } class MyClass : public MyClassInterface { public: double foo(double a) { // complex computation dependent on P1, P2, P3 } // more methods and fields (dependent on P1, P2, P3) } 

Параметры шаблона P1 , P2 , P3 находятся в ограниченном диапазоне, например, от 0 до некоторого фиксированного значения n зафиксированного во время компиляции.

Теперь я хотел бы построить «фабричный» метод, например

 MyClassInterface* Factor(int p1, int p2, int p3) { return new MyClass(); // <- how to do this? } 

Вопрос заключается в том, как достичь построения classа шаблона, когда параметры шаблона известны только во время выполнения. И возможно ли это с параметрами шаблона, имеющими очень большой домен (например, двойной)? Пожалуйста, учтите также, что возможное решение расширяется для использования большего количества параметров шаблона.

Вот что вы можете сделать:

 MyClassInterface* Factor(int p1, int p2, int p3) { if (p1 == 0 && p2 == 0 && p3 == 0) return new MyClass<0,0,0>(); if (p1 == 0 && p2 == 0 && p3 == 1) return new MyClass<0,0,1>(); etc; } 

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


Я также использовал этот бит кода прежде, чем сделать автоматическое создание нескольких шаблонов:

 #include  #define RANGE ((0)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)) #define MACRO(r, p) \ if (BOOST_PP_SEQ_ELEM(0, p) == var1 && BOOST_PP_SEQ_ELEM(1, p) == var2 && BOOST_PP_SEQ_ELEM(2, p) == var3 && BOOST_PP_SEQ_ELEM(3, p) == var4) \ actual_foo = foo; BOOST_PP_SEQ_FOR_EACH_PRODUCT(MACRO, RANGE RANGE RANGE RANGE) #undef MACRO #undef RANGE 

Компилятор производит вывод, который выглядит так:

 if (0 == var1 && 0 == var2 && 0 == var3 && 0 == var4) actual_foo = foo<0, 0, 0, 0>; if (0 == var1 && 0 == var2 && 0 == var3 && 1 == var4) actual_foo = foo<0, 0, 0, 1>; if (0 == var1 && 0 == var2 && 0 == var3 && 2 == var4) actual_foo = foo<0, 0, 0, 2>; if (0 == var1 && 0 == var2 && 0 == var3 && 3 == var4) actual_foo = foo<0, 0, 0, 3>; if (0 == var1 && 0 == var2 && 0 == var3 && 4 == var4) actual_foo = foo<0, 0, 0, 4>; if (0 == var1 && 0 == var2 && 0 == var3 && 5 == var4) actual_foo = foo<0, 0, 0, 5>; if (0 == var1 && 0 == var2 && 0 == var3 && 6 == var4) actual_foo = foo<0, 0, 0, 6>; if (0 == var1 && 0 == var2 && 0 == var3 && 7 == var4) actual_foo = foo<0, 0, 0, 7>; if (0 == var1 && 0 == var2 && 0 == var3 && 8 == var4) actual_foo = foo<0, 0, 0, 8>; etc... 

Кроме того, обратите внимание, что с помощью этого метода с 4 переменными, каждый из которых будет содержать более 13 значений, вы должны заставить компилятор создать экземпляр 28561 этой функции. Если вашему n было 50, и у вас все еще было 4 варианта, вы бы создали 6250000 функций. Это может сделать для компиляции SLOW.

Если macros не являются вашей вещью, вы также можете генерировать шаблоны if-then-else с помощью шаблонов:

 #include  #include  const unsigned int END_VAL = 10; class MyClassInterface { public: virtual double foo (double) = 0; }; template class MyClass : public MyClassInterface { public: double foo (double a) { return P1 * 100 + P2 * 10 + P3 + a; } }; struct ThrowError { static inline MyClassInterface* create (int c1, int c2, int c3) { throw std::runtime_error ("Could not create MyClass"); } }; template struct Factory : ThrowError {}; template struct Factory<0, END_VAL, N2, N3> : ThrowError {}; template struct Factory<1, N1, END_VAL, N3> : ThrowError {}; template struct Factory<2, N1, N2, END_VAL> : ThrowError {}; template struct Factory<0, N1, N2, N3> { static inline MyClassInterface* create (int c1, int c2, int c3) { if (c1 == N1) { return Factory<1, N1, 0, 0>::create (c1, c2, c3); } else return Factory<0, N1 + 1, N2, N3>::create (c1, c2, c3); } }; template struct Factory<1, N1, N2, N3> { static inline MyClassInterface* create (int c1, int c2, int c3) { if (c2 == N2) { return Factory<2, N1, N2, 0>::create (c1, c2, c3); } else return Factory<1, N1, N2 + 1, N3>::create (c1, c2, c3); } }; template struct Factory<2, N1, N2, N3> { static inline MyClassInterface* create (int c1, int c2, int c3) { if (c3 == N3) { return new MyClass (); } else return Factory<2, N1, N2, N3 + 1>::create (c1, c2, c3); } }; MyClassInterface* factory (int c1, int c2, int c3) { return Factory<>::create (c1, c2, c3); } 

Поскольку тесты вложены, он должен быть более эффективным, чем решение макроса шара.

Вы можете расширить его до большего количества параметров, добавив больше случаев глубины.

То, что не представляется возможным, шаблоны создаются во время компиляции.
К тому времени, когда у вас есть исполняемый файл, у вас есть только classы (конкретные экземпляры этих шаблонов), нет шаблонов.

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

Это технически возможно *, но это не практично, и почти наверняка это неправильный подход к решению проблемы.

Есть ли причина, почему P1, P2 и P3 не могут быть правильными целыми переменными?


* Вы можете встроить компилятор C ++ и копию своего источника, затем скомпилировать динамическую библиотеку или общий объект, который реализует вашу фабричную функцию для заданного набора P1, P2, P3, но вы действительно хотите это сделать? ИМО, это абсолютно безумная вещь.

Я не знаю, применимо ли это к вашей текущей проблеме, но, похоже, что C ++ 11 constexpr может быть тем, что вы ищете – функции constexpr могут вызываться во время выполнения и в то же время могут выполняться во время компиляции ,

Использование constexpr также имеет дополнительные преимущества от «более чистого» взгляда, чем использование TMP, работающего с любыми значениями времени выполнения (а не только с интегральными значениями), сохраняя при этом большинство преимуществ TMP, таких как мемонирование и время выполнения компиляции, хотя это несколько дано к решению компилятора. Фактически, constexpr обычно намного быстрее, чем эквивалентная версия TMP.

Обратите также внимание на то, что в целом использование шаблонов во время выполнения подрывает одну из самых больших возможностей шаблона. Тот факт, что они обрабатываются во время компиляции и в значительной степени исчезают во время выполнения.

Вы не можете. шаблон – это время компиляции.

Во время компиляции вы можете построить все возможные значения шаблонов и выбрать один из них во время выполнения.

слишком поздно, я знаю, но как насчет этого:

 // MSVC++ 2010 SP1 x86 // boost 1.53 #include  #include  // test #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  // test #include  /*! \internal */ namespace detail { /*! \internal */ namespace runtime_template { /*! \internal fwd */ template < typename Template , typename Types , typename Map // top level map iterator , typename LastMap // top level map iterator , int Index , bool Done = std::is_same::value > struct apply_recursive_t; /*! \internal fwd */ template < typename Template , typename Types , typename Map // top level map iterator , typename LastMap // top level map iterator , typename First , typename Last , int Index , bool Enable = !std::is_same::value > struct apply_mapping_recursive_t; /*! \internal run time compare key values + compile time push_back on \a Types */ template < typename Template , typename Types , typename Map // top level map iterator , typename LastMap // top level map iterator , typename First , typename Last , int Index // current argument , bool Enable /* = !std::is_same::value */ > struct apply_mapping_recursive_t { typedef void result_type; template  inline static void apply(const TypeIds& typeIds, T&& t) { namespace mpl = boost::mpl; typedef typename mpl::deref::type key_value_pair; typedef typename mpl::first::type typeId; // mpl::int if (typeId::value == std::get(typeIds)) { apply_recursive_t< Template , typename mpl::push_back< Types , typename mpl::second::type >::type , typename mpl::next::type , LastMap , Index + 1 >::apply(typeIds, std::forward(t)); } else { apply_mapping_recursive_t< Template , Types , Map , LastMap , typename mpl::next::type , Last , Index >::apply(typeIds, std::forward(t)); } } }; /*! \internal mapping not found \note should never be invoked, but must compile */ template < typename Template , typename Types , typename Map // top level map iterator , typename LastMap // top level map iterator , typename First , typename Last , int Index > struct apply_mapping_recursive_t< Template , Types , Map , LastMap , First , Last , Index , false > { typedef void result_type; template  inline static void apply(const TypeIds& /* typeIds */, T&& /* t */) { BOOST_ASSERT(false); } }; /*! \internal push_back on \a Types template types recursively */ template < typename Template , typename Types , typename Map // top level map iterator , typename LastMap // top level map iterator , int Index , bool Done /* = std::is_same::value */ > struct apply_recursive_t { typedef void result_type; template  inline static void apply(const TypeIds& typeIds, T&& t) { namespace mpl = boost::mpl; typedef typename mpl::deref::type Mapping; // [key;type] pair vector apply_mapping_recursive_t< Template , Types , Map , LastMap , typename mpl::begin::type , typename mpl::end::type , Index >::apply(typeIds, std::forward(t)); } }; /*! \internal done! replace mpl placeholders of \a Template with the now complete \a Types and invoke result */ template < typename Template , typename Types , typename Map , typename LastMap , int Index > struct apply_recursive_t< Template , Types , Map , LastMap , Index , true > { typedef void result_type; template  inline static void apply(const TypeIds& /* typeIds */, T&& t) { namespace mpl = boost::mpl; typename mpl::apply< mpl::unpack_args