2010-07-24 3 views
4

Прежде всего, чтобы объяснить, что я пытаюсь сделать:Переходя условие в качестве параметра

void Foo(int &num, bool condition); 

Foo(x, x > 3); 

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

void Foo(int &num, bool condition) 
{ 
    while(!condition) 
    { 
     num = std::rand(); 
    } 
} 

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

Заранее спасибо

+1

Есть ли увеличенная картинка, чтобы мы могли видеть «Foo» (притворяться, что это работает так, как вы хотите) в реальной ситуации? Кроме того, вы передаете 'x' в качестве параметра, когда это ссылка, а не адрес' x'. – GManNickG

+1

Если это 'std :: rand()' обратите внимание, что он возвращает 'int' и не принимает аргументов. –

+0

Да, я не проверял, я просто написал это, чтобы дать представление о том, как все должно работать. Мне очень жаль, что код смехотворный, но я написал его через несколько минут прямо здесь. @GMan - ну, я могу скопировать и вставить код, но может случиться, что он пропустит некоторые части, поэтому я просто хотел дать эту идею. То, что он должен делать, - это запросить пользователя для ввода снова и снова, пока условие не соблюдается. – Johnny

ответ

11

Одним из примеров использования стандартной библиотеки functor:

#include <functional> 

template<class UnaryPred> void func(int& num, UnaryPred predicate) { 
    while(!predicate(num)) num = std::rand(); 
} 

void test() { 
    int i = 0; 
    func(i, std::bind1st(std::greater<int>(), 3)); 
} 

Посмотреть документацию на <functional> для того, что уже предоставляет C++ с вне коробки.

Если ваш компилятор имеет достаточную поддержку (например, GCC 4.5 или VC10), вы также можете перейти на lambda functions. Например. используя тот же func(), как описано выше:

func(i, [](int num) { return num > 3; }); 
+0

Скорее всего, именно то, что мне нужно, и, скорее всего, принятый ответ, просто хочу проверить его и посмотреть, как это работает. О функции лямбда (я использую VC10), как мне вызвать ее в функции? – Johnny

+0

Точно так же, как в 'func()' в первом примере: 'predicate (someNumber)'. Выражение лямбда также генерирует функтор в фоновом режиме, а именно, что компилятор делает это для вас, и вы получаете гораздо более хороший синтаксис. –

+0

О, извините, я думал, что последний код не зависит от кода выше. Так что это всего лишь упрощенная функция func? Благодаря! – Johnny

2

Что вы должны сделать, это создать функцию, которая проверяет ваше состояние, а затем передать указатель на эту функцию в качестве параметра. См. http://www.cprogramming.com/tutorial/function-pointers.html для получения дополнительных сведений/руководств о том, как это сделать.

+0

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

+0

Да, это именно то, что я должен был делать с синтаксическим разбором строк. Или я чего-то не хватает? – Johnny

1

Передайте функцию вместо Foo. Затем вы можете «задержать» выполнение выражения, ожидая вызова этой функции.

2

Правдоподобный способ сделать это передал бы функтор - и объект, который ведет себя как функция - вызываемой функции, а вызываемая функция вызовет функтор для переоценки условия на каждой итерации цикла.

Разбор строки не будет работать; вызываемая функция не имеет доступа к локальным переменным вызывающей функции.

+0

Строковый подход основан на том, что он используется для ввода данных пользователя, поэтому проверяется только одна переменная, которая может быть передана в качестве ссылки и назначена на результат, если входной сигнал соответствует условию , В противном случае функторы - это то, что мне нужно, спасибо, проголосуйте. – Johnny

3

это называется функциональным программированием.

здесь фрагмент кода, используя подталкивание :: феникс http://www.boost.org/doc/libs/1_43_0/libs/spirit/phoenix/doc/html/phoenix/starter_kit.html:

using namespace boost::phoenix; 

Foo(x, (cref(x) < 3)); 
// (cref(x) < 3) is expression that creates function object 

template<class C> // condition is a monster, make it generic 
void Foo(int &num, C condition) 
{ 
    while(!condition()) // notice you call condition as function 
    { 
     rand(num); 
    } 
} 
1

Как уже сказал, передать объект функтор в Foo(). STL обычно использует этот подход. Например:

template< class Func > 
void Foo(int &num, Func condition) 
{ 
    while(!condition()) 
    { 
     rand(num); 
    } 
} 

struct GreaterThanThree 
{ 
    int& _num; 
    GreaterThanThree(int &num) : _num(num) {} 
    bool operator()() const { return (_num > 3); } 
}; 

Foo(x, GreaterThanThree(x)); 
+0

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

+0

@ Джонни: Это функтор. @Remy: Чтобы позволить функтору иметь изменяемое состояние, 'Foo' должен принимать' Func & condition' по ссылке. – rwong

+0

@rwong: конечно, если вам нужно пройти один и тот же объект-функтор несколько раз. Это не распространено. Я только когда-либо видел функторы, используемые с временными экземплярами, подобно тому, как я показывал. –

1

Вы можете сделать это без шаблонов или повышения (в комментатора называется это «C-стиль», который является правильным, я полагаю).

/* have Foo take a pointer to a function that returns bool */ 
void Foo(int &num, bool (*fcn)(int)) 
{ 
    while(!fcn(num)) 
    { 
     num = std::rand(); 
    } 
} 

/* You can have all the Comparators you want, 
    as long as they have the same signature */ 
bool ComparatorOne(int x) { return x > 3 ? true : false; } 

bool ComparatorTwo(int x) { return x < 10 ? true : false; } 

/* and this is how you call it */ 
int n; 
Foo(n, ComparatorOne); 
Foo(n, ComparatorTwo); 

Редактировать

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

+0

Прошу прощения, что мой вопрос непонятен, но мне это нужно для любого рода условий, а не только для целых чисел. Это должно быть универсальным. В любом случае, спасибо за подсказку и пример такого решения, проголосуйте! – Johnny

+0

Это C-образное решение, а не C++. C++ использовал бы функторы или лямбда (если ваш компилятор их поддерживает). – Sjoerd

+0

Я согласен, что это решение в стиле C, но оно работает, и это легко понять. – egrunin