在c ++ 11中,如何调用任意可调用对象?

时间:2015-10-03 03:41:43

标签: c++ callable

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

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

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

3 个答案:

答案 0 :(得分:7)

这正是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;
}

答案 1 :(得分:6)

不要自己实施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 :(得分:0)

使用boost::hof::apply

#include <boost/hof/apply.hpp>

// ...
boost::hof::apply(f, args...);

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


或者,使用boost::hana::apply,它执行相同的操作