c++ - 无法通过 std::ref() 使用 auto& 参数调用 std::invoke()

标签 c++ c++11 lambda c++17

我正在尝试创建一个 Invoker对象,它存储一个仿函数和该仿函数的一组参数 - 全部按值(用于线程)。 Invoker::operator()()将使用复制的参数调用存储的仿函数。

到目前为止一切正常,直到有人试图通过 auto& 传递一个参数使用 std::ref(variable) .具体来说,此代码应该可以工作,但它不会使用给定的错误消息进行编译:

int var = 0;
Invoker{
    [](auto& r) {
        printf("%d\n", r);
    }, std::ref(var)
}();

我希望它的工作方式类似于 std::thread适用于此示例。 错误信息是:

test.cpp:65:14: error: no matching function for call to ‘invoke(std::__tuple_element_t<0, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >, std::__tuple_element_t<1, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >)’
   std::invoke(std::get<Indicies>(std::move(args))...);
   ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我当前的 Invoker类:

template<typename... Args>
struct Invoker {
    std::tuple<std::decay_t<Args>...> args;

    explicit Invoker(Args... args)
        : args(std::forward<Args>(args)...)
    { }

    template<size_t... Indices>
    void _Invoke(std::index_sequence<Indices...>) {
        std::invoke(std::get<Indices>(std::move(args))...);
    }

    void operator()() {
        _Invoke(std::make_index_sequence<std::tuple_size_v<decltype(args)>>{});
    }
};

/* Invoker deduction guide (perfectly forward any parameters with full type!) */
template<typename Function, typename... Args>
Invoker(Function&&, Args&&...) -> Invoker<Function&&, Args&&...>;

See here对于这个问题的在线版本。错误消息表明,auto& 的推导类型是std::reference_wrapper<int>& , 当它应该是 int& .不幸的是,我想不出解决这个问题的办法。

编辑:

如评论所示,表达式

int var = 5;
std::thread{ [](auto& r) { printf("%d\n", r); }, std::ref(var) };

仅使用 gcc >= 7.1.0 编译.我很高兴看到关于这个主题的详细说明,特别是如果这是 c++ 标准的正确行为。

最佳答案

INVOKE 通常不会解包 reference_wrapper 参数;它们按原样使用(有一个异常(exception)与此处无关:如果您使用 reference_wrapper 作为第一个参数调用指向成员的指针,则该参数将被展开)。因此,invoke([](auto&){}, std::ref(var)); 将尝试使用右值 reference_wrapper 调用 lambda,这是不正确的为尝试将右值绑定(bind)到左值引用而形成。

观察到的 std::thread 行为是 libstdc++ bug已修复。简而言之,libstdc++ 的 std::thread 将提供的参数存储在一个 tuple 中,它是(错误地)用 make_tuple 构建的(它解包了 reference_wrappers).

关于c++ - 无法通过 std::ref() 使用 auto& 参数调用 std::invoke(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48948986/

相关文章:

java - 如何传递参数化 lambda 的构造函数引用?

c++ - 创建链表时使用 new 运算符

c++ - 访问未定义子类型时的自定义编译错误消息

lambda - 计算素数(流和 lambda)

c++ - GNU g++ 4.9.2 查找函数调用的编译错误

c++ - 如何在编译时检查像 "#define VERSION 3.1.4"这样的值?

c++ - Qt - 无法让 lambda 工作

c++ - 如何使用 C++ 在一行中声明和定义多个变量?

c++ - Ruby on Rails 在后台工作 [resque + resque-status]

c++ - c++中cin的功能