3

I would like to create function calling another function and printing its arguments.
It should be compatible with many functions (returning the same result) with many combinations of variables of arguments.

I would like to have something like this:

int fun1(){}
int fun2(int i){}
int fun3(std::string s, int i){}

void execute_and_print(std::function f, ...)
{
///code
}

int main()
{
execute_and_print(&fun1);
execute_and_print(&fun2, 3);
execute_and_print(&fun3,"ff",4);
}

It could print:

executed function with arguments:
executed function with arguments: 3
executed function with arguments: ff, 4

Is it even possible in C++?

pktiuk
  • 235
  • 5
  • 10
  • 1
    Look up "call forwarding" in C++ tag, you'll find multiple solutions. The key is to make `execute_and_print` a variadic template. This way it would be able to call any function that you pass it. It wouldn't be of type `std::function`, though. – Sergey Kalinichenko Jan 25 '21 at 14:20
  • There's no point in converting it to std::function because it's going to be templated anyway. – user202729 Jan 25 '21 at 14:29
  • 2
    See [c++ - Using fold expressions to print all variadic arguments with newlines inbetween - Stack Overflow](https://stackoverflow.com/questions/43070062/using-fold-expressions-to-print-all-variadic-arguments-with-newlines-inbetween) for the printing part. – user202729 Jan 25 '21 at 14:30

3 Answers3

5

In C++17 it is very simple

template <typename F, typename... Args>
void execute_and_print(F f, Args... args)
{
    (std::cout << ... << args);
    f(args...);
}

Prior to that there is extra ceremony

template <typename F, typename... Args>
void execute_and_print(F f, Args... args)
{
    int dummy[] = { (static_cast<void>(std::cout << args), 0)... };
    f(args...);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • First and the second examples didn't work in MSVC C++17 and C++14. – D-RAJ Jan 25 '21 at 15:01
  • First example: error: expected ‘;’ before ‘<<’ token std::cout << ... << args; Second one: error: too many decimal points in number int dummy[] = { static_cast(std::cout << args), 0... }; – pktiuk Jan 25 '21 at 15:03
  • 1
    @pktiuk: typos should be fixed now. – Jarod42 Jan 25 '21 at 17:03
2

It is not foolproof, but any possible errors will be caught at compile time (ie. the code will not compile). It should work file, as long as the provided parameters match those of the called function, and a matching << operator exists for each parameter.

template<class Fn, class...Args>
void execute_and_print(Fn fn, Args...args) {
    int f[sizeof...(Args)] = { (std::cout << args << ", ", 0)... };
    fn(args...);
}

Refer to https://en.cppreference.com/w/cpp/language/parameter_pack. The sizeof... command is actually the number of elements, not their combined size.

IWonderWhatThisAPIDoes
  • 1,000
  • 1
  • 4
  • 14
2

You can use templates to get it done,

template <class... Args>
void RunThrough(Args&& ... args)
{
    ([&](auto& input)
        {
            std::cout << input << ", ";
        } (args), ...);
}

template<class Func, class... Args>
decltype(auto) execute_and_print(Func f, Args&&... args)
{
    f(args...);

    std::cout << "executed function with arguments: ";
    RunThrough(args...);
    std::cout << std::endl;
}

You can use lambdas, std::function objects and function pointers in this.

Reference: https://stackoverflow.com/a/60136761/11228029

D-RAJ
  • 3,263
  • 2
  • 6
  • 24