【问题标题】:Deduce the std::function result type and use it as a parameter推导出 std::function 结果类型并将其用作参数
【发布时间】:2017-06-06 10:00:19
【问题描述】:

这就是我的简单类的样子。

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 或函数指针) 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 中的方法,但无济于事。

【问题讨论】:

  • decltype 不计算其操作数,因此不会构造任何额外内容。存在不可默认构造的T 的问题,std::declval 涵盖了该问题。但我不明白你的“非简化案例”是如何工作的。
  • 另外,您的代码中绝对没有 std::function —— lambda 不是 std::function
  • 好吧,也许我把它简化了一点。在我的情况下 f 需要 3 个参数,我不知道其中两个的类型,我只知道它们与返回类型相同,所以我不能真正使用 decltype,因为我不知道什么 dummy我应该在评估中创建类。
  • 你需要处理重载的函数吗?如果是这样,您想在哪里解决歧义?
  • 好吧,我想出了一个很好的例子——假设我们有一个二叉树,我们想要遍历它,并得到一些结果。所以 f 接受三个参数:来自节点的值、来自左子树的值和来自右子树的值。从子树返回的值可以是任何类型,但它需要与 f 的返回类型相同。不增加新的模板参数能推导出来吗?

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


【解决方案1】:

您可以随意为decltype 创建复杂的参数。

decltype 在编译时进行评估,不会生成任何代码。编译器将在“dry-run”模式下完成构建所有参数的动作,找出结果返回类型并使用它。

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

【讨论】:

    【解决方案2】:

    假设没有重载的函数,我们可以实现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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 1970-01-01
      • 1970-01-01
      • 2013-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多