将函数的返回值存储在元组中

Storing return values of functions in a tuple

本文关键字:元组 存储 返回值 函数      更新时间:2023-10-16

考虑

#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);
}

有什么好的变通方法可以让酒吧返回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时,它才有效。我会尽量让它在任何一般情况下都能工作。或者像Steve建议的那样使用std::可选。

#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);
}

滥用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>
}

您可以使用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);
}

现场演示

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

值得注意的是,有一个建议是将void作为常规类型,这样可以避免所有这些麻烦,但我不确定这是什么状态,也不确定它是否会被接受。