А теперь для полного изменения направления от указателей на функции C ++ - PullRequest
2 голосов
/ 03 июня 2010

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

В устаревшем коде есть массив const, заполненный перечислимым типом. Приходит команда, она просматривается в таблице, а затем отправляется в оператор switch с ключом перечисляемого типа.

Перечисление типов имеет выбор VALID_BUT_NOT_SIMULATED, который фактически является запретным с точки зрения сима. Мне нужно превратить эти команды в команды для других вещей [новые имитированные биты | живые биты. Новые и живые вещи имеют интерфейсы, отличные от старых [что заставляет меня смеяться над дурацкой работой, которая потребовалась, чтобы все это произошло, но это тема для другого обсуждения].

Мне нравится массив, потому что это очень удачное описание живой вещи, которую этот блок имитирует [защелкивание цепочек по строкам и столбцам]. Я думал, что попытаюсь заменить перечисленные типы в массиве указателями на функции и вызвать их напрямую. Это было бы вместо переключателя поиска +.

Ответы [ 4 ]

3 голосов
/ 03 июня 2010

Не может быть сделано. Тем не менее, вы можете сделать что-то вроде этого с функтором. Я поместил пример кода, но когда я писал его, я понял, что такая конструкция обязательно будет довольно сложной. Вы можете посмотреть на boost :: bind для некоторых идей.

2 голосов
/ 03 июня 2010

Один из способов сделать это, хотя и некрасиво, - использовать универсальную таблицу указателей и привести ваши указатели функций к такому универсальному типу (теряя информацию о типах аргументов):

void (*myFunctions[]) () = {
    (void (*)())myFirstFunction,
    (void (*)())mySecondFunction
};

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

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

((void (*)(int))tab[0])(1);

Для вызова myFirstFunction с x = 1.

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

1 голос
/ 03 июня 2010

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

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

0 голосов
/ 03 июня 2010

В исходном вопросе вы описывали сценарий, который очень распространен при работе с библиотеками Javascript. В Javascript библиотеки часто предоставляют возможность «заинтересованным сторонам» получать уведомления о событиях, публикуемых библиотекой, и все, что нужно сделать заинтересованным сторонам, - это зарегистрировать свои собственные Function обратные вызовы объектов. В одной версии библиотеки в документации может быть сказано, что обратным вызовам будут переданы n аргументы (a, b, c, ... в этом порядке), но будущая версия Возможно, вы захотите предоставить n + m аргументов. Это изменение не должно нарушать существующий код, потому что библиотека может просто добавить дополнительные m аргументы в список аргументов, и это работает, потому что Javascript использует соглашение о вызовах для очистки вызывающего абонента (по сути).

В C ++ вы могли бы сделать нечто подобное (предоставить дополнительные аргументы для обратных вызовов), при условии, что вы можете гарантировать, что соглашение о вызовах, используемое обратными вызовами и для обратных вызовов, является вызывающим-очищающим соглашения о вызовах, например C для архитектуры x86 :

#include <cstdlib>
#include <iostream>
#include <vector>

extern "C" void old_api_callback_in_old_archive(int x) {
    std::cout << "`old_api_callback_in_old_archive` was called with x = " << x << std::endl;
}

extern "C" void new_api_callback(int x, int otherInfo) {
    std::cout << "`new_api_callback` was called with x = " << x
        << ", otherInfo = " << otherInfo << std::endl;
}

extern "C" {
    typedef void (*callback_type)(int, int);
}

int main()
{
    std::vector<callback_type> callbacks;
    callbacks.push_back(&new_api_callback);
    callbacks.push_back(reinterpret_cast<callback_type>(&old_api_callback_in_old_archive));

    std::vector<callback_type>::iterator it;
    for (it = callbacks.begin(); it != callbacks.end(); ++it) {
        (*it)(7, -8);
    }

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