Can't add perfect forwarding to wrapper function
Asked Answered
B

2

3

While answering this question I wrote this working code, wrapping function passed in template arguments:

template<typename Fn, Fn fn, typename... Args>
auto wrapper(Args... args)->decltype(fn(args...)){
    return fn(args...);
}
#define WRAPPER(FUNC) wrapper<decltype(&FUNC), &FUNC>

Example usage (I use this code for testing):

int min(int a, int b){
    return (a<b)?a:b;
}

#include<iostream>
using std::cout;
int main(){
    cout<<WRAPPER(min)(10, 20)<<'\n';
}

Two people told me to use perfect forwarding. When I asked how to do this, one of them redirected me here. I read question, carefully read best answer, and changed wrapper to:

#include<utility>
template<typename Fn, Fn fn, typename... Args>
auto wrapper(Args&&... args)->decltype(fn(std::forward<Args...>(args...))){
    return fn(std::forward<Args...>(args...));
}

It compiles, unless I attempt to check it out using example code above. How can I fix the code?

http://rextester.com/YUIYI99787

Bodily answered 20/8, 2014 at 14:48 Comment(0)
C
5

You have the dots in the wrong place on the return statement. You want:

return fn(std::forward<Args>(args)...);

This will expand to:

return fn(std::forward<T1>(t1), std::forward<T1>(t2), ...);

What you wrote would have expanded to:

return fn(std::forward<T1,T2,...>(t1, t2, t3)); 

The trick is that everytime you see "...", think "it will replicate the thing behind it". This can get tricky because there are all sorts of ways to construct the "thing behind it", including being able to do a cross-product and the like.

Compton answered 20/8, 2014 at 14:53 Comment(0)
G
3
#include<utility>
template<typename Fn, Fn fn, typename... Args>
auto wrapper(Args&&... args)->decltype(fn(std::forward<Args>(args)...)){
//                             vvvvvvvvvv---- Oopsie ! ----^^^^^^^^^^
    return fn(std::forward<Args>(args)...);
}

On each line, the single ellipsis will expand both Args and args in parallel. You will end up with :

std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ...

... rather than the incorrect :

std::forward<Arg1, Arg2, ...>(arg1, arg2, ....)

You might also be interested in std::result_of to trim that declatation a bit :

#include<utility>
template<typename Fn, Fn fn, typename... Args>
auto wrapper(Args&&... args) -> std::result_of<Fn(Args...)>::type {
    return fn(std::forward<Args>(args)...);
}
Giddings answered 20/8, 2014 at 14:51 Comment(2)
It must be an English error from me then, because they definitely mean the same thing for me... could you help me rephrasing mine maybe ?Giddings
Nope, never mind, my fault I read it backwards. I think it's because you talk about the solution in the present tense "this does this", whereas Jared talks about the solution in the future tense "this will do this" and it got me all confused.Ahmad

© 2022 - 2024 — McMap. All rights reserved.