【问题标题】:Storing return values of functions in a tuple将函数的返回值存储在元组中
【发布时间】:2017-11-16 22:05:25
【问题描述】:

考虑

#include <tuple>

template <typename... F>
auto execute (F... f) {
    return std::make_tuple(f(0)...);
}

int foo(int) { return 5; }
int bar(int) { return 3; }

int main() {
    auto tuple = execute(foo, bar);
}

有什么好的解决方法可以让 bar 返回 void?

我试过这个,但它不会编译:

#include <tuple>

struct Void { };

template <typename T>
T check(T n) { return n; }

Void check(void) { return Void{}; }

template <typename... F>
auto execute (F... f) {
    return std::make_tuple(check(f(0))...);
}

int foo(int) { return 5; }
void bar(int) { }

int main() {
    auto tuple = execute(foo, bar);
}

更新:我有一个暂定的解决方案,但它仅在我们知道传递的参数始终为 int 0 时才有效。我将尝试使其在任何一般设置中都有效。或者也许像史蒂夫建议的那样使用 std::optional 。

#include <tuple>
#include <type_traits>

struct Void { };

template <typename F>
auto execute_h (F f, std::enable_if_t<!std::is_void_v<std::result_of_t<F(int)>>>* = nullptr) {
    const auto result = f(0);
    return result;  
}

template <typename F>
auto execute_h (F f, std::enable_if_t<std::is_void_v<std::result_of_t<F(int)>>>* = nullptr) {
    f(0);
    return Void{};  
}

template <typename... F>
auto execute (F... f) {
    return std::make_tuple(execute_h(f)...);
}

int foo(int) { return 5; }
void bar(int) { }

int main() {
    auto tuple = execute(foo, bar);
}

【问题讨论】:

标签: c++ function c++11 templates tuples


【解决方案1】:

滥用operator , 的重载(因为void(), T 不会调用自定义operator,):

#include <tuple>

struct Void {};

template <typename T>
T&& operator , (T&& t, Void) { return std::forward<T>(t); }

template <typename... Fs>
auto execute (Fs... fs) {
    return std::make_tuple((f(0), Void{})...);
}

int foo(int) { return 5; }
void bar(int) { }

int main() {
    auto tuple = execute(foo, bar); // tuple<int, Void>
}

【讨论】:

    【解决方案2】:

    您可以使用std::enable_if 和包装函数为返回void 的函子返回Void 对象:

    #include <tuple>
    #include <type_traits>
    
    struct Void { };
    
    template <typename Func, typename... Args>
    auto check(Func func, Args&&... args)
        -> std::enable_if_t<!std::is_void<decltype(func(std::forward<Args>(args)...))>::value, decltype(func(std::forward<Args>(args)...))>
    {
        return func(std::forward<Args>(args)...);
    }
    
    template <typename Func, typename... Args>
    auto check(Func func, Args&&... args)
        -> std::enable_if_t<std::is_void<decltype(func(std::forward<Args>(args)...))>::value, Void>
    {
        func(std::forward<Args>(args)...); return Void{};
    }
    
    template <typename... F>
    auto execute (F... f) {
        return std::make_tuple(check(f, 0)...);
    }
    
    int foo(int) { return 5; }
    void bar(int) { }
    
    int main() {
        auto tuple = execute(foo, bar);
    }
    

    Live demo

    这有点重复,但它可以为任何类型的函子、任何参数列表和任何返回类型完成工作。

    值得注意的是,有一个 proposal 浮动以使 void 成为常​​规类型,可以让您避免所有这些麻烦,但我不确定它的状态是什么,或者它是否会成为接受。

    【讨论】:

    • is_void 更简单。
    • @Walter 忘记了is_void。已更新。
    猜你喜欢
    • 2021-11-28
    • 2016-11-23
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多