【问题标题】:In c++ 11, how to invoke an arbitrary callable object?在 c++ 11 中,如何调用任意可调用对象?
【发布时间】:2015-12-31 08:14:31
【问题描述】:

可调用的概念在http://en.cppreference.com/w/cpp/concept/Callable中定义。

假设我有一个可调用对象 f,它有一个类型为 T* 的参数并返回类型为 voidf 可以是任何可调用类型(函数对象、指向成员函数的指针、指向数据成员的指针等)。如何调用 f

仅仅调用 f(x) 会失败,因为 f 可以是指向成员函数或数据成员的指针。有没有简单的方法来调用f?一种可能的解决方案是 std::bind(f, x)(),但是当 f 有更多参数时,这个解决方案会变得更加复杂。

【问题讨论】:

  • 你有用例吗?

标签: c++ callable


【解决方案1】:

与其自己实现INVOKE,不如使用library features that uses it 之一。特别是,std::reference_wrapper 有效。这样就可以得到std::invoke(f, args...)std::ref(f)(args...)的效果:

template<typename F, typename... Args>
auto invoke(F f, Args&&... args)
    -> decltype(std::ref(f)(std::forward<Args>(args)...))
{
    return std::ref(f)(std::forward<Args>(args)...);
}

我没有转发f,因为std::reference_wrapper 要求传入的对象不是右值。使用std::bind 而不是std::ref 并不能解决问题。这意味着对于这样的函数对象:

struct F
{
    void operator()() && {
        std::cout << "Rvalue\n";
    }
    void operator()() const& {
        std::cout << "Lvalue\n";
    }
};

invoke(F{}) 将打印 Lvalue,而 C++17 中的 std::invoke(F{}) 将打印 Rvalue

我从this paper找到了技术

【讨论】:

    【解决方案2】:

    这正是 std::invoke 所做的,但直到 C++17 才成为标准。您可以制作自己的版本,但如果完全通用,则可能会非常复杂。

    以下是两种情况的基本思路(代码取自 cppreference.com):

    template <class F, class... Args>
    inline auto INVOKE(F&& f, Args&&... args) ->
        decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
          return std::forward<F>(f)(std::forward<Args>(args)...);
    }
    
    template <class Base, class T, class Derived>
    inline auto INVOKE(T Base::*pmd, Derived&& ref) ->
        decltype(std::forward<Derived>(ref).*pmd) {
          return std::forward<Derived>(ref).*pmd;
    }
    

    【讨论】:

    【解决方案3】:

    使用boost::hof::apply:

    #include <boost/hof/apply.hpp>
    
    // ...
    boost::hof::apply(f, args...);
    

    boost::hof::apply 执行与INVOKE 相同的操作。


    或者,使用boost::hana::apply,它做同样的事情

    【讨论】:

      猜你喜欢
      • 2021-07-31
      • 1970-01-01
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      相关资源
      最近更新 更多