С++ Универсальный способ вызвать любую функцию дважды

Проблема состоит в следующем: мне необходимо вызвать функцию саму себя ещё раз в случае, если она вернёт false.

Казалось бы, всё очень просто. Но таких функций очень много, и аргументы они принимают разные.

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

Проблема в том, что в каждой функции писать это сравнение сложно, долго и опасно.

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

Define, например, бы вставлял название функции и её аргументы (как я себе представляю)

bool doSmth(int val)
{
    if (res == false) {
        static thread_local bool called = false;
        if (called) {
            called = false;
        }
        else {
            called = true;
            return doSmth(val);            
        }  
    }
    return res;
}

Было бы хорошо, если блок if заменить на какой-нибудь макрос или функцию, например:

bool doSmth(int val)
{
    bool res = compute(val);
    return CALL_FUNC_AGAIN_IF_FALSE(res);
}

В этом случае функция выполняется ещё один раз, затем возвращается результат независимо от того, true или false.


Ответы (2 шт):

Автор решения: bipll

return called || doSmth(val); или о чем?

bool doSmth(int val, bool retry = true)
{
    return compute(val) || retry && doSmth(val, false);
}

? Ну или что-нибудь вроде

template<class F, class... Args> auto at_most_twice(F &&f, Args &&...args) {
    return std::invoke(f, args...) || std::invoke(f, std::forward<Args>(args)...);
}

Class instance;
at_most_twice(&Class::method, instance, arg1, arg2);
→ Ссылка
Автор решения: avp

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

bool ff(const char *t) {
  puts(t);
  return t[0] == '2';
}

bool fff(const char *t, const char *s) {
  puts(t); puts(s);
  return t[0] == '2';
}

#define call2(f, ...) (f(__VA_ARGS__) || f(__VA_ARGS__))

int main()
{
  call2(ff, "123");
  call2(fff, "abc", "xxx");
  call2(fff, "22", "333");
}

Подробнее о макросах с переменым числом аргументов можно прочесть тут.

Вызываем

avp@avp-desktop:~/avp/hashcode$ g++ t.cpp -O3
avp@avp-desktop:~/avp/hashcode$ ./a.out
123
123
abc
xxx
abc
xxx
22
333
avp@avp-desktop:~/avp/hashcode$ 

Это?

→ Ссылка