我不明白限定符在何处/为何被丢弃。
#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
答案 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.a
时c
的常量(参见本答案的结尾)。
&A::f
f()
成员函数允许您在const
对象上调用它。const
,则std::ref(a)
不会保留c
但a
的副本,std::reference_wrapper<A>
适用于operator()
的方式}是不同的(见本答案的结尾)。std::reference_wrapper<A>
进行捕获时,[&]
不再是c
,因此您可以在const
上调用非const成员函数。额外的详细信息(仍来自this):
如果存储的参数
c.a
属于arg
类型(例如,在std::reference_wrapper<T>
的初始调用中使用了std::ref
或std::cref
,那么上面bind
调用中的参数vn
为std::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
和相应的类型arg
为Vn
,其中T cv &
与cv
的cv资格相同。
所以原始调用等同于(因为g
是const,所以c
是cv
):
const
其中std::invoke(&A::f, std::forward<A const&>(c_a));
是c_a
内A
的副本。
答案 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;
}