Список функций C++

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

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

Я думал о классическом массиве функций, но моя главная проблема в том, что массив функций будет сложно поддерживать и немного уродлив. (Цель состоит в том, чтобы собрать каждую пару функций в отдельный файл, сократить время компиляции и упростить управление кодом.) Есть ли у кого-нибудь более элегантное решение C++ в качестве альтернативы массиву функций? Скорость на самом деле не проблема, меня больше беспокоит ремонтопригодность.

-Nicholas

8 ответов

Решение

Вы могли бы написать что-то вроде:

class EncryptionFunction
{
public:
    virtual Foo Run(Bar input) = 0;
    virtual ~MyFunction() {}
};

class SomeSpecificEncryptionFunction : public EncryptionFunction
{
    // override the Run function
};

// ...

std::vector<EncryptionFunction*> functions;

// ...

functions[2]->Run(data);

Вы могли бы использовать operator() вместо Run в качестве имени функции, если вы предпочитаете.

Что не так с массивом функций?

Вам нужно вызывать функции по индексу. Таким образом, они должны быть каким-то образом помещены в некую структуру, "индексируемую по индексу". Массив, вероятно, самая простая структура, которая удовлетворяет этой потребности.

Пример (печатать у меня в голове, может не скомпилироваться):

struct FunctionPair {
   EncodeFunction encode;
   DecodeFunction decode;
};
FunctionPair g_Functions[] = {
   { MyEncode1, MyDecode1 },
   { MySuperEncode, MySuperDecode },
   { MyTurboEncode, MyTurboDecode },
};

Что является "уродливым" или "трудным для поддержания" в подходе выше?

Попробуйте класс Loki::Functor. Больше информации на CodeProject.com

Если вы смотрели в boost::signals библиотека, вы увидите очень хороший пример, который очень элегантный:
Предположим, у вас есть 4 функции, такие как:

void print_sum(float x, float y)
{
  std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
  std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
  std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
  std::cout << "The quotient is " << x/y << std::endl;
}

Тогда, если вы хотите назвать их элегантным способом, попробуйте:

boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

И вывод:

The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667

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

int Proto1( void );
int Proto2( void );
int Proto3( void );

int (*functinPointer[3])( void ) =
{
   Proto1,
   Proto2,
   Proto3
};

Тогда вы можете сделать что-то вроде этого:

int iFuncIdx = 0;
int iRetCode = functinPointer[iFuncIdx++]();

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

Затем создайте вектор стратегий и используйте его вместо списка функций.

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

// functiontype.h
typedef bool (*forwardfunction)( double*, double* );

// f1.h
#include "functiontype.h"
bool f1( double*, double* );

// f1.c
#include "functiontype.h"
#include "f1.h"
bool f1( double* p1, double* p2 ) { return false; }


// functioncontainer.c    
#include "functiontype.h"
#include "f1.h"
#include "f2.h"
#include "f3.h"

forwardfunction my_functions[] = { f1, f2, f3 };
  • Объявление функции и определения находятся в отдельных файлах - время компиляции в порядке.
  • Группировка функций находится в отдельном файле, имеющем зависимость только от объявлений

Вы можете взглянуть на библиотеку Boost.Signals. Я считаю, что он имеет возможность вызывать свои зарегистрированные функции с помощью индекса.

Объект с определенным методом operator() может вести себя как функция, но в целом работать с ним приятнее.

Другие вопросы по тегам