Deduce std :: function结果类型并将其用作参数

时间:2017-01-21 13:53:00

标签: c++ c++11 templates functional-programming

这就是我的简单课程的样子。

template <class T>
class A {
T first;
T second;

public:
A(T f, T s) : first(f), second(s) {};

template <class F>
auto foo(F f) -> decltype(f(T(), T())) {
    return f(first, second);
}
};

int main() {
    A<int> a = A<int>(2, 3);
    a.foo([](int l, int r)->int{return l + r;});
}

我希望foo接受一个函数(或lambda或fucntion指针)f,它接受类型T的两个属性并返回f()的结果。

此代码有效,但我创建了伪参数以获取decltype的结果。在这种情况下,这些是简单的整数,但它可以是任何东西,我当然不希望从更大的类构造虚拟参数。如何处理?

此外,这只是一个简化的案例。就我而言,foo看起来像那样:

foo(function f, result_type_of_f t1, result_type_of_f t2) {
    // do something
    return f(first, second, t1, t2);
}

我不能用与第一个类似的方法来做,我也尝试过这篇文章中的方法Determining return type of std::function,但无济于事。

2 个答案:

答案 0 :(得分:2)

随意创建decltype的参数复合体。

在编译时评估

decltype,导致不生成代码。编译器将完成构造所有参数的动作,在“干运行”模式下,找出返回的返回类型,然后使用它。

对于复杂的C ++代码,由于decltype,模板和其他构造函数,编译器必须完成的所有工作确实会降低编译速度;但是decltype最终导致没有运行时开销,无论decltype d是什么。

答案 1 :(得分:1)

假设没有重载的函数体来打扰,我们可以实现resultOf类型特征来检索返回类型:

// std::void_t from C++17
template <class...>
struct voider {
    using type = void;
};

template <class... T>
using void_t = typename voider<T...>::type;

namespace detail_resultOf {

    // Base case, when it cannot be deduced
    template <class F, class = void_t<>>
    struct resultOf { };

    // Function object: grab its operator() and try again
    template <class F>
    struct resultOf<F, void_t<decltype(&F::operator())>>
    : resultOf<decltype(&F::operator())> { };

    // Member functions
    template <class Ret, class T, class... Args>
    struct resultOf<Ret (T::*)(Args...)> {
        using type = Ret;
    };

    // ...

    // Free functions

    template <class Ret, class... Args>
    struct resultOf<Ret (*)(Args...)> {
        using type = Ret;
    };

    // ...
}

// Public metafunction
template <class F>
using resultOf = typename detail_resultOf::resultOf<F>::type;

See it live on Coliru

然后你可以把你的功能写成:

template <class F>
auto foo(F f, resultOf<F> t1, resultOf<F> t2) -> resultOf<F> {
    // do something
    return f(first, second, t1, t2);
}