Search code examples
c++templatesc++14

Function argument returning void or non-void type


I am in the middle of writing some generic code for a future library. I came across the following problem inside a template function. Consider the code below:

template<class F>
auto foo(F &&f) {
    auto result = std::forward<F>(f)(/*some args*/);
    //do some generic stuff
    return result;
}

It will work fine, unless I pass to it a function that returns void like:

foo([](){});

Now, of course, I could use some std::enable_if magic to check the return type and perform specialization for a function returning void that looks like this:

template<class F, class = /*enable if stuff*/>
void foo(F &&f) {
    std::forward<F>(f)(/*some args*/);
    //do some generic stuff
}

But that would awfully duplicate code for actually logically equivalent functions. Can this be done easily in a generic way for both void-returning and non-void-returning functions in a elegant way?

EDIT: there is data dependency between function f() and generic stuff I want to do, so I do not take code like this into account:

template<class F>
auto foo(F &&f) {
    //do some generic stuff
    return std::forward<F>(f)(/*some args*/);
}

Solution

  • if you can place the "some generic stuff" in the destructor of a bar class (inside a security try/catch block, if you're not sure that doesn't throw exceptions, as pointed by Drax), you can simply write

    template <typename F>
    auto foo (F &&f)
     {
       bar b;
    
       return std::forward<F>(f)(/*some args*/);
     }
    

    So the compiler compute f(/*some args*/), exec the destructor of b and return the computed value (or nothing).

    Observe that return func();, where func() is a function returning void, is perfectly legal.