0

I would like to use a function as argument in a variadic template, why does the following not work? How do I make it work?

template<typename F, typename... Args>
F test(F f, const Args&&... args) {
return f(std::forward<Args>(args)...);
}

int simple(int i) { 
    return i; 
}


int main()
{
    std::cout << test(simple, 2); // error, 'std::forward': none of the 2 overloads could convert all the argument types
}

2 Answers 2

3

There are a couple of problems with your code.

First of all, you should use forwarding references, so you need to change const Args&&... to Args&&....

Then, test does not have to return F. So it is reasonable to use decltype(auto) here.

In addition to that, it makes sense to forward f too.

The fixed version might look like this:

template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
    return std::forward<F>(f)(std::forward<Args>(args)...);
}

WANDBOX EXAMPLE

Sign up to request clarification or add additional context in comments.

3 Comments

Why is it that when I add the 'test' function and the 'simple' function to a basic class, 'Tester', as public functions, and in main do: Tester t; std::cout << t.test(t.simple, 2); It no longer works, it says it cannot find a matching overloaded function, and Tester::simple non-standard syntax; use &...
@Alexander Shortly, because simple becomes a member function. You cannot pass member functions to the test function written above. At least, you have to provide an instance on which call the member function. Look at std::invoke for further details: en.cppreference.com/w/cpp/utility/functional/invoke
@EdgarRokjān it makes sense to forward f too. <--- could you please explain why? The only situation I can think of is if we use a functor instead of a function pointer, so that functor might be an rvalue, but it's not the case here
0

The first problem is the return type. Your test function returns F which is a function pointer. Instead change it to auto to automatically deduce the return type.

The second issue is that std::forward requires a non-const reference.

You might use trailing return type:

template<typename F, typename... Args>
auto test(F f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
    return f(std::forward<Args>(args)...);
}

But decltype(auto) (C++14 required) is a simpler solution:

template<typename F, typename... Args>
decltype(auto) test(F f, Args&&... args) {
    return f(std::forward<Args>(args)...);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.