C++ 将函数对象赋值给函数包装器后出现意外行为

C++ 将函数对象赋值给函数包装器后出现意外行为,c++,c++11,object-slicing,C++,C++11,Object Slicing,我在一个应用程序中搜索一个bug,我最终修复了它,但没有完全理解。 可使用以下简单程序再现该行为: #包括 #包括 #包括 结构Foo { 虚int运算符()(void){return 1;} }; 结构栏:公共Foo { 虚拟int运算符()(void)重写{return 2;} }; int main() { std::shared_ptr p=std::make_shared(); std::cout指针的静态类型p是Foo 所以在这个声明中 f = *p; 左操作数*p的类型为Foo,

我在一个应用程序中搜索一个bug,我最终修复了它,但没有完全理解。 可使用以下简单程序再现该行为:

#包括
#包括
#包括
结构Foo
{
虚int运算符()(void){return 1;}
};
结构栏:公共Foo
{
虚拟int运算符()(void)重写{return 2;}
};
int main()
{
std::shared_ptr p=std::make_shared();

std::cout指针的静态类型
p
Foo

所以在这个声明中

f = *p;

左操作数
*p
的类型为
Foo
,即存在切片。

这是常规切片,隐藏在
std::function
std::shared\u ptr
层下

f = *p;
是有效的,因为
*p
是一个可调用的对象,具有适当的
运算符()
,这是可以包装在
std::function
中的内容之一

它不起作用的原因是它复制了
*p
——这是一个
Foo&
,而不是
条&

对上一个示例的此改编将表现出相同的行为:

Bar b;
Foo& c = b;
std::function<int(void)> f1 = c;
std::cout << f1() << std::endl;
条b;
Foo&c=b;
std::函数f1=c;

std::cout对象切片发生在这里

点被赋予
f=*p;
p
std::shared\u ptr
类型,那么
*p
的类型是
Foo&
(而不是
条&
)。即使参数通过引用,但

4) 将
*this
的目标设置为可调用的
f
,就像执行
函数(std::forward(f)).swap(*this);

请注意,上面的
F
也被推断为
Foo&
。通过值获取参数,对象切片发生,效果是
F
是从
*p
切片复制的
Foo
类型的对象赋值的

模板
功能(F);
切片 这是一个切片的例子。 原因是
std::function
的赋值运算符(也在另一个示例中演示),该运算符表示:

将*this的目标设置为可调用的f,就像执行 函数(std::forward(f)).swap(*this);。此运算符不 参与重载解析,除非f可为参数调用 类型Args…和返回类型R(从C++14开始)

如果简化并精简示例,您可以很容易地看到发生了什么:

Foo* p =  new Bar;

Foo f;
f = *p;//<-- slicing here since you deref and then copy the object
一个更合适的解决方案也可以是只使用
reference\u wrapper

f = std::ref(p);

我想知道你在std::function的内部会发生什么,它会导致调用Bar::opeeator()。赋值应该如何工作?@n.m.我没想到会发生什么,这是一个bug,我必须在一些不是我编写的代码中找到它。+1用于显示解决方法。然而,这段代码“简化”的原因是对于<代码> fof**p;可以使用更多的解释。抱歉,但我没有要求一个解决办法。正如我提到的,我修复了bug,实际上我是用lambda做的。我要求的是一个详细的解释。RabBID76当然,我提到了这些解决方案/解决方案主要是为了其他用户来这里。但是我会更新我的答案。短。
f = [p]{return (*p)();};
f = std::ref(p);