Подтвердить что ты не робот

Шаблон функции как аргумент шаблона

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


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

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, чтобы избежать избыточности кода. Я могу сделать это с помощью указателей функций или шаблонов. Позвольте мне выбрать последнее на данный момент. Мое мышление заключается в том, что это лучше, поскольку компилятор, несомненно, сможет встроить функции - я прав? Могут ли компиляторы по-прежнему встроить вызовы, если они сделаны с помощью указателей функций? Это побочный вопрос.

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

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() в последнем примере?

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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 должен быть более сложным, чем ваш пример, вы можете столкнуться с проблемами, но это намного проще, чем все, что я смог придумать.

Ответ 3

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