丢弃限定符未知原因(std :: bind()/ lambda)

时间:2018-01-16 09:32:09

标签: c++ c++11 lambda stdbind qualifiers

我不明白限定符在何处/为何被丢弃

#include <iostream>
#include <memory>

class A {
public:
    void f() {};
};

template <typename Callable>
void invoker(Callable c) {
    auto l = [=]() {
        c(); // <------------------- Error
    };
    l();
}

int main() {
    A a;
    invoker(std::bind(&A::f, a));
    return 0;
}

我在 c(); 行上遇到编译器错误:

  

错误:传递'const std :: _ Bind(A)&gt;'为   '_Result std :: _ Bind&lt; _Functor(_Bound_args)的'this'参数   ...)&gt; :: operator()(_ Args&amp;&amp; ...)[with _Args = {}; _Result = void;   _Functor = std :: _ Mem_fn; _Bound_args = {A}]'丢弃限定符[-fpermissive]            C();

我不明白的解决方法:

  • 将A :: f()定义为const: void f() const {};

  • bind()对实例a的引用: invoker(std :: bind(&amp; A :: f, std :: ref(a)));

  • 通过lambda传递给ref自动l = [&amp; ](){

g ++版本:

g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4

2 个答案:

答案 0 :(得分:4)

根据this

  

std::bind的返回类型包含由std::decay<F>::type构造的std::forward<F>(f)类型的成员对象,以及每个args...的一个对象,类型为std::decay<Arg_i>::type ,类似地从std::forward<Arg_i>(arg_i)构建。

这意味着c包含a的副本(让我们称之为c.a),但由于您通过副本捕获c,{{ 1}}是c - 在lambda内限定,const&#34;继承&#34;调用c.ac的常量(参见本答案的结尾)。

  • 使&A::f f()成员函数允许您在const对象上调用它。
  • 如果您使用const,则std::ref(a)不会保留ca的副本,std::reference_wrapper<A>适用于operator()的方式}是不同的(见本答案的结尾)。
  • 通过引用std::reference_wrapper<A>进行捕获时,[&]不再是c,因此您可以在const上调用非const成员函数。

额外的详细信息(仍来自this):

  

如果存储的参数c.a属于arg类型(例如,在std::reference_wrapper<T>的初始调用中使用了std::refstd::cref,那么上面bind调用中的参数vnstd::invoke,同一调用中的arg.get()类型为Vn:存储的参数通过引用传递到调用函数对象。

所以使用T&的电话相当于:

std::ref(a)

std::invoke(&A::f, std::forward<A&>(c_a.get())); 位于c_a内的std::reference_wrapper<A>。请注意,转发类型为c,而不是A&

  

否则,普通存储的参数A const&将作为lvalue参数传递给invokable对象:上面arg调用中的参数vn只是std::invoke和相应的类型argVn,其中T cv &cv的cv资格相同。

所以原始调用等同于(因为g是const,所以ccv):

const

其中std::invoke(&A::f, std::forward<A const&>(c_a)); c_aA的副本。

答案 1 :(得分:3)

霍尔特给出了很好的答案。

如果您无法将A :: f修改为const方法,则可以使lambda变为可变:

#include <iostream>
#include <memory>
#include <functional>

class A {
public:
    void f() {};
};

template <typename Callable>
void invoker(Callable c) {
    auto l = [=]() mutable // <-- Fixed
    {
        c(); 
    };
    l();
}

int main() {
    A a;
    invoker(std::bind(&A::f, a));
    return 0;
}