2011-01-15 4 views
26

Я только что запутался, как реализовать что-то в общем виде на C++. Это немного запутанно, поэтому позвольте мне объяснить шаг за шагом.Шаблон функции как аргумент шаблона


Рассмотрим такой код:

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 


void function1() { 
    a(123); 
    a(456); 
} 
void function2() { 
    b(123); 
    b(456); 
} 

void test() { 
    function1(); 
    function2(); 
} 

Это легко заметно, что function1 и function2 сделать то же самое, с той лишь другая часть является внутренней функцией.

Поэтому я хочу сделать function generic, чтобы избежать избыточности кода. Я могу сделать это с помощью указателей функций или шаблонов. Позвольте мне выбрать последнее на данный момент. Мое мышление заключается в том, что это лучше, поскольку компилятор, несомненно, сможет встроить функции - я прав? Могут ли компиляторы по-прежнему встроить вызовы, если они сделаны с помощью указателей функций? Это побочный вопрос.

OK, вернуться к исходной точке ... Раствор с шаблонами:

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 

template<void (*param)(int) > 
void function() { 
    param(123); 
    param(456); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

Все ОК. Но я столкнулся с проблемой: могу ли я это сделать, если a и b являются самими дженериками?

template<typename T> 
void a(T t) { 
    // do something 
} 

template<typename T> 
void b(T t) { 
    // something else 
} 

template<...param...> // ??? 
void function() { 
    param<SomeType>(someobj); 
    param<AnotherType>(someotherobj); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

Я знаю, что параметр шаблона может быть одним из:

  • типа,
  • типа шаблона,
  • значения типа.

Ничто из этого не касается моей ситуации. Мой главный вопрос: Как это решить, т. Е. Определить function() в последнем примере?

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

ответ

25

Чтобы решить эту проблему с помощью шаблонов, вы должны использовать параметр шаблона шаблона. К сожалению, вы не можете передавать шаблон шаблона в качестве типа, потому что он должен быть создан первым. Но есть обходное решение с фиктивными структурами. Вот пример:

template <typename T> 
struct a { 

    static void foo (T = T()) 
    { 
    } 

}; 

template <typename T> 
struct b { 

    static void foo (T = T()) 
    { 
    } 

}; 

struct SomeObj {}; 
struct SomeOtherObj {}; 

template <template <typename P> class T> 
void function() 
{ 
    T<SomeObj>::foo(); 
    T<SomeOtherObj>::foo(); 
} 

int main() 
{ 
    function<a>(); 
    function<b>(); 
} 
+0

Не совсем уверен, почему это произошло. Это не совсем удовлетворительно, но оно решает проблему. –

+0

Итак, чтобы подвести итог: единственное решение, позволяющее встроить вызовы, - заменить функции функторами? Думаю, немного громоздко, но вполне приемлемо. Благодаря! – Kos

+1

Но я признаю, что я очень удивлен, когда вы сказали, что невозможно встроить адресный вызов ... Если адрес может быть определен во время компиляции равным адресу данной функции, я бы ожидал, компилятор достаточно умный. :) Strange ... – Kos

0

Вот путь. Это не может быть лучше, но это работает:

template <typename T, T param> 
void function() { 
    param(123); 
    param(456); 
} 

void test() 
{ 
    function< void(*)(int), a<int> >(); // space at end necessary to compiler 
    function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous 
} 

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

EDIT: Хорошо, сейчас я немного ушел и пропустил часть, где параметры имеют разные типы. Виноват.

Там может быть сложным способом сделать это с помощью шаблонов, но это самый простой способ, которым я мог думать:

#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0) 

Я знаю, я знаю, «макросы злы,» бла-бла-бла. Оно работает. Если function должен быть более сложным, чем ваш пример, вы можете столкнуться с проблемами, но это намного проще, чем все, что я смог придумать.

+0

Но обратите внимание, что 'function' хочет вызвать различную инстанциацию функции шаблона параметра. – Kos

+0

@ Kos - «# define» не может быть и речи? –

+0

Ну, это _is_ «последнее средство», которое будет работать :), но неудобно редактировать, отлаживать, не может быть в пространстве имен ... Я бы предпочел найти решение на основе шаблонов, а не на основе препроцессора. – Kos

-2
template < typename F > 
void function(F f) 
{ 
    f(123); 
} 

void a(int x) { ... } 

struct b { void operator() (int x) { ... } }; 

void outer() 
{ 
    function(&a); 
    function(b()); 
} 
+0

Это не то, что хотел OP. –

+1

Спасибо, но это не связано с проблемой, которую я описал. В этом случае данный вызов 'function' использует только 1 экземпляр функции параметра/функтора. Пожалуйста, прочитайте этот вопрос еще раз. – Kos

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