Функция шаблона в качестве аргумента шаблона - PullRequest
29 голосов
/ 15 января 2011

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

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

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

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

Ответы [ 4 ]

27 голосов
/ 15 января 2011

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

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 голосов
/ 31 мая 2019

С лямбдой из C ++ 11 вы можете сделать:

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

template <typename F>
void function(F&& f) {
    f(someobj);
    f(someotherobj);
}

void test() {
    // For simple cases, auto&& is even probably auto or const auto&
    function([](auto&& t){ a(t); });
    function([](auto&& t){ b(t); });

    // For perfect forwarding
    function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
    function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
}

Могут ли компиляторы по-прежнему выполнять вызовы, если они выполняются через указатели функций?

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

0 голосов
/ 15 января 2011
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 голосов
/ 15 января 2011

Вот способ.Возможно, это не лучший вариант, но он работает:

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
}

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

РЕДАКТИРОВАТЬ: Ладно, я сегодня немного ушел и пропустил ту часть, где параметры разных типов.Мой плохой.

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...