2013-04-17 6 views
1

Допустим, я хочу только вызвать одну функцию в моем коде: func(), но в зависимости от того, какое значение я ей даю, пусть это будет ПРЯМОЙ к правильной «версии» этой функции?Как вызвать функцию на основе входного значения?

Я знаю, что это можно было бы сделать с операторами if-statements/switch-statements, но тогда было бы (неэффективно) проверять, какое значение было передано. Я надеялся, что есть готовый способ сделать это?

Возможно ли сделать это как можно эффективнее?

func(3) 

выполнит третью версию FUNC()

func[1]{ 
    cout "One"; 
} 

func[2]{ 
    cout "Two"; 
} 

func[3]{ 
    cout "Three"; 
} 
+0

Если вы называете свои функции 'func1',' func2' и 'func3' , вы можете использовать препроцессор: '#define func (x) funC## x()'. Я уверен, что есть больше возможностей C++ - ey, но я не эксперт по этой теме, боюсь. –

+0

Хотелось бы, чтобы вы использовали пример, который не заставил всех неверно истолковать ваш вопрос. – paddy

+0

Принимаете ли вы свой вход от внешнего источника или он известен во время компиляции? Это может повлиять на полученные ответы. –

ответ

-1

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

0

Когда вы делаете func(3), где аргумент (ы) постоянны, компилятор автоматически оптимизирует функцию, если у нее нет побочных эффектов. Это означает, что функция не может изменять глобальную переменную, переменную-член или записывать любые указатели, переданные функции. Операторы if исчезнут во время выполнения.

2

На самом деле, case-switch очень эффективен, потому что даже если у вас очень большое количество целей, он может скомпилировать это в коде как таблицу прыжков, а не как цепочку ifs - так что все части переключатель будет равным количеством инструкций.

http://en.wikipedia.org/wiki/Switch_statement#Compilation

Если диапазон входных значений опознаваемый «малый» и имеет лишь несколько пробелов, некоторые компиляторы, которые включают оптимизатор может фактически реализовать оператор коммутатора в виде таблицы филиала или массив из указателей на индексированные функции вместо длинной серии условных инструкций . * Это позволяет оператору switch мгновенно определить, какая ветка выполнить, не пройдя через список сравнений.

Кроме того:

1) Не беспокойтесь о преждевременной оптимизации, если вы не указали код, как узкое место, который замедляя вашу программу вниз.

2) Почему вызов функции с разными значениями делает ее совершенно другой? Разве это не разные функции? (Если вы хотите, чтобы вызвать кучу функций в цикле, вы всегда можете создать массив указателей на функции - смотрите указатели функций)

+0

Спасибо, это очень хорошо известно, что коммутатор эффективен именно так. – Tez

6

Вы могли бы иметь массив указателей на функции:

int foo_1() { 
    cout << "One"; 
} 

// ... 

auto[] functions = {foo_1, foo_2, foo_3}; 

и назовите его

functions[0](); 
+0

черт: P почему я об этом не думал. Определенно больше того, чего хочет искатель, чем шаблонные функции. –

+0

Честно говоря, это решение воняет C, и, вероятно, существует «более C++» решение. – Tordek

+1

Это может быть быстрее, если имеется значительное количество опций. Однако, когда утверждения if настолько просты, косвенная ветвь, вероятно, будет медленнее из-за проблем с прогнозом ветвления/эффективностью трубопровода. –

0

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

Например

template< int subfunc> 
void func< subfunc>(); 

void func<1>(); 

Что-то, как это должно работать :)

Таким образом, когда вы называете это вы говорите: func<1>(); и он будет вызывать другую функцию.

Только что проверил. Это решение не будет работать так, как пожелает пользователь, поскольку введенное значение в шевронах должно быть постоянным/компилируемым значением времени.

0

Поскольку мы жесткие люди, использующие C++ здесь, я хотел бы использовать map из string (ваш вход) в void * (представляет все функции), и таким образом, мне не нужно будет рассчитывать на какой-либо определенном порядке моего вызываемые функции на карте. Я также не нужно, чтобы преобразовать входной сигнал на число (в случае, если вход с консоли, и это строка)

#include <map> 
#include <string> 
#include <iostream>  // for cout 

using namespace std; // that's the way I like it 

int main() 
{ 
    map<string, void *> funcs; 

    funcs["func1"] = (void *)func1; 
    funcs["func2"] = (void *)func2; 
    ... 

    string s = myinput(); 
    if (funcs.find(s) != funcs.end()) { 
     ((void (*)())funcs[s])(); // call the function (first casting it to the function's data type 
    } 
    else cout << "### Error: function " << s << " doesn't exist in map" << endl; 

    return 0; 
} 
+1

Поскольку мы uber жесткие люди, использующие C++, давайте не будем использовать стили C или отливки, которые не нужны. –

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