2016-03-27 4 views
6

Я работаю над фреймворком, который поможет в создании шаблонов функций. У меня есть куча функций, шаблонных по целочисленному значению для целей оптимизации, которые необходимо создать и выбрать во время выполнения. Пример использования заключается в следующем:Нужна помощь Очистка шаблона Мгновенная структура

// Function to instantiate templates of. 
template<int a, int b, int c> void MyFunction(float, double){}; 

// List of values to substitute into each template parameter. 
typedef mpl::vector_c< int, 7, 0, 3, 4, 2> valuesToInstantiate; 
int numberOfValuesPerParameter = size<valuesToInstantiate>::type::value; 

// Function pointer type. Must define type for array to hold template instantiations. 
typedef void (*MyFunctionPointer)(float, double); 

// Array to hold template instantiations. 
// Accessed at runtime to get proper instantiation. 
MyFunctionPointer arrayOfTemplateInstantiations[numberOfValuesPerParameter*numberOfValuesPerParameter*numberOfValuesPerParameter]; 

// Passed to template instantiation framework. 
// AddTemplate member function will be called once per template value combo (3 int values). 
// templateIndex indicates where to store the instantation in the array. 
// templateSequence contains the template value combo (3 int values). 
template<int templateIndex, typename templateSequence> 
struct MyFunctionTemplateCreator 
{ 
    static void AddTemplate(void) 
    { 
     // Store template instantiation in array. 
     arrayOfTemplateInstantiations[templateIndex] = MyFunction 
     < 
     mpl::at<templateSequence, mpl::int_<0> >::type::value, 
     mpl::at<templateSequence, mpl::int_<1> >::type::value, 
     mpl::at<templateSequence, mpl::int_<2> >::type::value 
     >; 
    } 
}; 

// List of lists where each inner list contains values to instantiate 
// for the corresponding template parameter. E.g. each value in the first 
// inner list will be passed into the first template parameter of MyFunction 
typedef mpl::vector< valuesToInstantiate, valuesToInstantiate, valuesToInstantiate > templatesToCreate; 

// Call template instantation framework to instantiate templates. 
CreateTemplates<MyFunctionTemplateCreator, templatesToCreate> unusedVariable; 

// Call proper template instantation at runtime...using index 5 arbitrarily for example. 
arrayOfTemplateInstantiations[5](1.5, 2.0); 

Таким образом, в этом примере, я инстанцировании Моя_функция, который принимает целые значения 3, с каждой комбинацией { {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2} }. Я опустил реализацию CreateTemplates, поскольку он довольно длинный, но он реализован с использованием boost MPL for_each. Код, указанный выше, необходим для каждой функции, с которой я хочу это сделать, и, хотя она короче, чем запись явных экземпляров 512, это еще немного.

Удивительно, но самый длинный код, который должен быть записан для каждой функции, с которой я хочу это сделать, - это typedef указателя функции, так как многие из функций принимают 10 + аргументы. Есть ли способ сохранить эти экземпляры шаблонов в массиве более общего типа, каким-то образом обернув их?

Для аргументации можно предположить, что параметры шаблона всегда являются целыми значениями, такими как пример, так что сигнатуры экземпляров шаблона одинаковы для заданного шаблона функции. Выполняемые функции - это все в глобальном пространстве имен, никогда не функционируют в качестве членов (они на самом деле являются ядрами CUDA). Любые другие советы по его очистке будут оценены по достоинству.

Примечание: С помощью C++ 03

Edit: Я хотел бы задать вопрос, TarmoPikaro по поводу того, что я пытаюсь сделать.

Я работаю с приложением, в котором до 4 задач/потоков будет делиться графическим процессором для выполнения своей работы (такая же работа, разные данные). Поскольку некоторые из наших ядер CUDA используют текстуры, нам необходимо динамически раздавать доступные текстуры во время выполнения. Мы задерживаем поддержку унаследованных возможностей CUDA, потому что объекты текстуры не могут передаваться как аргументы функции и должны быть статическими глобальными переменными. Выдавать текстуры для процессора задач/нитей затем, мы выдаем индексы текстуры и наши CUDA ядро ​​имеет такие заявления:

// (variables t_int_2d_N are texture objects) 
if (maskTextureIndex == 0) 
    maskValue = tex2D(t_int_2d_0, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 1) 
    maskValue = tex2D(t_int_2d_1, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 2) 
    maskValue = tex2D(t_int_2d_2, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 3) 
    maskValue = tex2D(t_int_2d_3, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 4) 
    maskValue = tex2D(t_int_2d_4, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 5) 
    maskValue = tex2D(t_int_2d_5, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 6) 
    maskValue = tex2D(t_int_2d_6, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 7) 
    maskValue = tex2D(t_int_2d_7, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 

Имея это утверждение в цикле в ядре неприемлемых потери производительности. Чтобы избежать потери производительности, мы подбираем ядро ​​по целочисленному значению (представляющему индекс текстуры) таким образом, что приведенный выше условный оператор компилируется. Ядро, которое содержит вышеуказанный код, будет создаваться с помощью maskTextureIndex, равным 0-7, поэтому у нас есть 8 разных ядер для выбора из среды выполнения. В некоторых наших ядрах используется до трех текстур, и мы допускаем каждый тип текстуры (например, float 1D, float 2D, float2 2D, int 3D и т. Д.), Чтобы иметь индексы 0-7, что означает, что мы должны создать экземпляр 8 * 8 * 8 = 512 различных ядер для компиляции трех разных условных операторов, подобных приведенным выше. Код в моем исходном вопросе используется для каждого ядра, использующего текстуры, чтобы создать экземпляр всех комбинаций.

+0

К сожалению, это так, что сам язык программирования может быть адаптирован каким-либо образом, о котором не говорили сами авторы языка программирования. Такое злоупотребление или злоупотребление языком возможно для экстремальных программистов, которые думают, что достигли Гайи и могут делать все, что захотят, с помощью языка. К сожалению, такой код становится сложным для дальнейшего развития и дальнейшего развития, и очень возможно, что во время последующих итераций другой разработчик, скорее всего, перепишет ваше решение. Может быть, вы можете более подробно указать, чего вы хотите достичь в конце? – TarmoPikaro

+0

@TarmoPikaro Наконец-то обратился к вашему вопросу. Не уверен, что есть лучшее решение без обновления до C++ 11. Надеюсь, что кто-то возьмет это как вызов;). – user1777820

ответ

1

С C++ 03 я не смог найти способ избежать написания функции typedef или способа уменьшить ее. С C++ 11 и decltype вы могли бы это определение типа во как это (если у вас нет каких-либо шаблонов с параметрами типа):

typedef decltype(&MyFunction<0, 0, 0>) MyFunctionPointer; 

С другой стороны, вы можете сделать некоторые из кода Вы копируете вокруг каждая функция, которую вы создаете, не нужна. В вашем примере вы объявили структуру MyFunctionTemplateCreator. Эта структура может быть изменена так, что ей требуется гораздо меньшая структура, чтобы обеспечить значение указателя функции для этого экземпляра.Вот более общий вариант структуры:

template< 
    typename Arg, 
    template <Arg, Arg, Arg> class TemplateClass, 
    typename Func, 
    Func* instantiationArray> 
struct FunctionTemplateCreator 
{ 
    template< 
     int templateIndex, 
     typename templateSequence> 
    struct InnerStruct 
    { 
     static void AddTemplate(void) 
     { 
      instantiationArray[templateIndex] = TemplateClass 
       < 
       mpl::at<templateSequence, mpl::int_<0> >::type::value, 
       mpl::at<templateSequence, mpl::int_<1> >::type::value, 
       mpl::at<templateSequence, mpl::int_<2> >::type::value 
       >::function(); 
     } 
    }; 
}; 

Вы только должны объявить эту структуру один раз и положить его в заголовке где-то. Он будет работать для каждой функции, которая имеет три идентичных параметра типа. Вот как вы могли бы использовать эту структуру для функции в вашем примере. Сначала вы объявляете все типы mpl::vector, которые используются для предоставления значений для создания экземпляров перегрузок шаблонов. Затем вы создаете структуру, которая предоставляет метод function(), который возвращает указатель на функцию перегрузки. Вот один, определенный для примера функции:

template<int a, int b, int c> 
struct MyFunctionTypedef 
{ 
    static MyFunctionPointer function() 
    { 
     return &MyFunction<a, b, c>; 
    } 
}; 

InnerStruct из FunctionTemplateCreator является то, что на самом деле передается в CreateTemplates. FunctionTemplateCreator служит только для пересылки параметров шаблона во внутреннюю структуру. Вот то, что переменная CreateTemplates будет выглядеть с этими новыми типами:

CreateTemplates<FunctionTemplateCreator<int, MyFunctionTypedef, MyFunctionPointer, arrayOfTemplateInstantiations>::InnerStruct, templatesToCreate> unusedVariable; 

Если вы начнете использовать C++ 11 метод function() в MyFunctionTypedef может быть constexpr.

+0

Я дал вам щедрость за то, что нашел время, чтобы посмотреть на нее, и потому, что я не мог найти лучшего ответа. Спасибо за помощь! Похоже, пришло время перейти на C++ 11. – user1777820

Смежные вопросы