В C ++ (*), возможно ли иметь структуру, которая откладывает некоторые вычисления до тех пор, пока они не понадобятся (и, возможно, никогда не выполняет вычисления, если в этом нет необходимости)? Мой вариант использования выглядит следующим образом: у меня есть примерно дюжина переменных типа bool, каждая из которых вычисляется с помощью вызова некоторой функции. После этого идет довольно длинный (и сложный) условный оператор, в котором эти переменные типа bool используются в различных комбинациях, чтобы определить, какое действие будет выполнять код следующим.
Вот несколько надуманных примеров кода, которые, надеюсь, лучше иллюстрируют то, что я делаю:
bool const b1 = func1(param1,param2,param3);
bool const b2 = func2(param4);
// ...
bool const b15 = func15(param35,param36,param37,param38);
if (b1 && !b5 && (b2 || b3)) { do_something1(); }
else if (b3 && !b15 || (b4 && b9 && b6)) { do_something2(); }
else if (b14 || b10 || (!b11 && b7)) { do_something3(); }
else if (b8) {
if (!b1 || !b6) { do_something4(); }
else if ( /* ... */ ) // ... etc
}
// ... and on and on
Это чисто надуманный пример, но, надеюсь, он иллюстрирует идею.
Ясно, что этот код можно было бы переписать без bools и функций, вызываемых непосредственно в большом условном операторе. Но я чувствую, что это сделает и без того непростой для чтения код еще более трудным для чтения и более подверженным ошибкам. И эта логика может измениться, поэтому я считаю, что bools также упрощают управление с точки зрения рефакторинга.
Более того, в условном выражении на любой тип bool можно ссылаться несколько раз; поэтому использование функций напрямую означает, что выполнение может дублироваться. (Я думал, что std :: bind может привести меня туда с точки зрения удобочитаемости; но он все равно потенциально вызовет любой из вызовов funcN () несколько раз.)
Я ищу лучшее из обоих слов, например, отложенное вычисление. Что, если вместо того, чтобы вычисляться и назначаться явно в начале кода, я мог бы сказать, только оценивать их по мере необходимости (и запоминать результат). Большой условный оператор таков, что, как правило, не все логические объекты нужно вычислять, чтобы определить, что будет дальше. Целью здесь является повышение производительности, поскольку этот код вызывается часто. Поэтому я стараюсь сократить объем работы, выполняемой на каждой итерации.
(*) Предпочтительно C ++ 14 (или старше), так как это то, что использует мой работодатель.
Изменить: Как насчет этого:
#include <iostream>
#include <functional>
//////////////////////////////////////////////////////////////////////////////
class Sum
{
public:
int sum(int const a, int const b) { ++n_calls_; return (a+b); }
int getNCalls() const { return n_calls_; }
private:
int n_calls_ = 0;
};
//////////////////////////////////////////////////////////////////////////////
template <class BoundFunc, typename RetType>
class DeferredCompute
{
public:
DeferredCompute(BoundFunc const& f) : func_(f) { }
RetType operator()()
{
if (!computed_)
{
value_ = func_();
computed_ = true;
}
return value_;
}
private:
bool computed_ = false;
RetType value_;
BoundFunc const& func_;
};
//////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
Sum s;
auto boundSum = std::bind(&Sum::sum, &s, 75, 25);
DeferredCompute<decltype(boundSum), int> deferredSum(boundSum);
// call function directly repeatedly
for (int i=0; i<5; ++i)
{
std::cout << "boundSum()=" << boundSum() << std::endl;
}
std::cout << "s.getNCalls()=" << s.getNCalls() << std::endl;
// should only call once
for (int i=0; i<5; ++i)
{
std::cout << "deferredSum()=" << deferredSum() << std::endl;
}
std::cout << "s.getNCalls()=" << s.getNCalls() << std::endl;
return 0;
}
Вывод:
boundSum()=100
boundSum()=100
boundSum()=100
boundSum()=100
boundSum()=100
s.getNCalls()=5
deferredSum()=100
deferredSum()=100
deferredSum()=100
deferredSum()=100
deferredSum()=100
s.getNCalls()=6
deferred
- person Alan Birtles   schedule 15.09.2020bool
, действует какbool
, но вызывает функцию при первой ссылке и использует ранее оцененный результат для всех последующих ссылок. - person Sam Varshavchik   schedule 15.09.2020