考虑
#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);
}
答案 0 :(得分:4)
滥用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>
}
答案 1 :(得分: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);
}
它有点重复,但它可以为任何类型的仿函数,任何参数列表和任何返回类型完成工作。
值得注意的是,proposal漂浮在{{}}周围,使void
成为一种常规类型,让您避免所有这些麻烦,但我不是确定它的状态是什么,或者它是否会被接受。