2016-01-12 3 views
0

У меня есть длинный алгоритм, который должен обрабатывать некоторые инструкции, описанные более чем одним #define, чтобы резко сократить исходный код. Например:Pass #define content как параметр

#define LongFunction(x, y, alg) return alg(x, y) 
#define Alg1(x, y) ((x)+(y)) 
#define Alg2(x, y) ((x)^((x)-(y))) 

И все, что мне нужно сделать, это

LongFunction(x, y, Alg1); 
LongFunction(x, y, Alg2); 

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

+5

Почему для всех, кто нечестив во Вселенной, вы используете макросы, подобные этому в C++? Если вы хотите решить проблемы с производительностью, прокомментируйте свой код и оптимизируйте по мере необходимости. То, что вы здесь делаете, - преждевременная оптимизация, и это хуже, чем Джастин Бибер. –

+1

Есть ли причина, по которой вам нужно уменьшить код таким образом, а не вызывать функции как обычно? Скорее всего, было бы лучше включить эти шаги в функции как обычные, и пусть компилятор позаботится об оптимизации. Если по-прежнему существует потребность в улучшении производительности, вы можете профилировать код. – danielunderwood

+0

@CaptainObvlious Это только упрощение того, что действительно происходит в моем коде. – user3040937

ответ

3

Существует множество способов параметризации функции.

Использование макросов может показаться простым, но макросы не уважают области применения, и есть проблемы с заменой параметров и побочными эффектами, поэтому они являются Evil™.

В C++ 11, а затем наиболее естественной альтернативой является использование std::function и лямбды, как это:

#include <functional>  // std::function 
#include <math.h>   // pow 
using std::function; 

auto long_function(
    double const x, 
    double const y, 
    function<auto(double, double) -> double> alg 
    ) 
    -> double 
{ 
    // Whatever. 
    return alg(x, y);  // Combined with earlier results. 
} 

auto alg1(double const x, double const y) 
    -> double 
{ return x + y; } 

auto alg2(double const x, double const y) 
    -> double 
{ return pow(x, x - y); } 

#include <iostream> 
using namespace std; 
auto main() -> int 
{ 
    cout << long_function(3, 5, alg1) << endl; 
} 

Что касается “ быстро, как это возможно ”, с современным компилятором код макроса является вряд ли будет быстрее. Но поскольку это важно, сделайте меру. Только измерения, для сборки релиза и в типичной среде исполнения, могут рассказать вам, что является самым быстрым и зависит ли скорость от конечного пользователя.

Из старого и формально вы можете использовать спецификатор inline, чтобы дать подсказку компилятору, что он должен обрабатывать встроенные вызовы кодов функции. Современные компиляторы, вероятно, просто проигнорируют inline для этого (у него есть еще один гарантированный смысл по сравнению с ODR). Но, вероятно, это не помешает применить его. Опять же, важно измерить. И обратите внимание, что результаты могут отличаться для компиляторов.

Одна из альтернатив вышеперечисленным - передать простой указатель на функцию. Это может быть быстрее, чем std::function, но менее общий. Тем не менее, в другом направлении вы можете templatize на типа с функцией-членом, и это дает компилятору больше информации, больше возможностей встроить, за счет того, что вы не можете, например. выберите операции из массива во время выполнения. Я считаю, что когда вы измеряете, если это достаточно важно, вы обнаружите, что templatization дает самый быстрый код. Или, по крайней мере, так быстро, как выше.


Пример templatizing на типа, что обеспечивает работу:

#include <math.h>   // pow 

template< class Op > 
auto long_function(double const x, double const y) 
    -> double 
{ 
    // Whatever. 
    return Op()(x, y);  // Combined with earlier results. 
} 

struct Alg1 
{ 
    auto operator()(double const x, double const y) 
     -> double 
    { return x + y; } 
}; 

struct Alg2 
{ 
    auto operator()(double const x, double const y) 
     -> double 
    { return pow(x, x - y); } 
}; 

#include <iostream> 
using namespace std; 
auto main() -> int 
{ 
    cout << long_function<Alg1>(3, 5) << endl; 
} 

Кстати, обратите внимание, что ^ не является оператором экспоненцирование в С ++ (она находится в например Visual Basic). В C и C++ это оператор bitlevel XOR. В приведенном выше коде я предположил, что вы действительно имели в виду возведение в степень, и использовал функцию pow от <math.h>.


Если, вместо этого, вы на самом деле имел в виду bitlevel XOR, то аргументы должны быть целыми числами (предпочтительно беззнаковых целых чисел), которые затем будут указывать, что вы хотите, типы аргументов для long_function в зависимости от типов аргументов для указанного операция. Это более сложная проблема, но включает либо перегрузку, либо шаблонизацию, либо и то, и другое. Если это то, что вы действительно хотите, пожалуйста, продумайте это.

+0

Учитывая, что это вопрос производительности, я бы предпочел не использовать 'std :: function'. Есть ли причина, по которой вы не сделали 'long_function'' шаблоном', который принимает любые вызываемые напрямую? – 5gon12eder

+1

@ 5gon12eder: Общность. Я не стал отвечать на него как вопрос производительности. Но я добавил несколько слов об этом. –

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