在元组

时间:2017-11-16 22:05:25

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

考虑

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

2 个答案:

答案 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);
}

Live demo

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

值得注意的是,proposal漂浮在{{}}周围,使void成为一种常规类型,让您避免所有这些麻烦,但我不是确定它的状态是什么,或者它是否会被接受。