Boost::any左值与右值重载解析异常原因排查
Boost::any重载无法区分左值/右值的原因分析
问题场景
你尝试实现函数重载,让函数分别接受boost::any左值和右值参数并表现不同行为,但实际运行结果不符合预期:
测试代码
#include <boost/any.hpp> #include <iostream> #include <string> #include <memory> class MyClass { public: MyClass() { a_int = -1; b_string = "abc"; } private: int a_int; std::string b_string; public: static void DumpMyClass(boost::any&& my_class_obj) { std::cout << "rvalue reference" << std::endl; } static void DumpMyClass(const boost::any& my_class_obj) { std::cout << "lvalue reference" << std::endl; } }; int main() { std::shared_ptr<MyClass> c_sptr = std::make_shared<MyClass>(); MyClass::DumpMyClass(c_sptr); MyClass::DumpMyClass(std::move(c_sptr)); return 0; }
编译输出
$clang++ -std=c++11 any.cc -o code && ./code rvalue reference rvalue reference
你原本期望调用MyClass::DumpMyClass(c_sptr);会匹配输出lvalue reference的函数。但如果将函数签名改为接受std::shared_ptr<MyClass>&和std::shared_ptr<MyClass>&&,则行为符合预期:
lvalue reference rvalue reference
核心原因
问题的本质是你传递的参数类型是std::shared_ptr<MyClass>,而非boost::any,编译器需要通过隐式类型转换生成临时boost::any对象,这导致了重载匹配的差异:
std::shared_ptr重载的正常逻辑- 传递左值
c_sptr时,std::shared_ptr<MyClass>&是精确匹配(无需任何转换),因此被选中; - 传递
std::move(c_sptr)(右值)时,std::shared_ptr<MyClass>&&是精确匹配,因此被选中。
- 传递左值
boost::any重载的异常逻辑
当传递c_sptr(std::shared_ptr左值)时,编译器需要先构造一个临时boost::any对象(将std::shared_ptr存入),这个临时对象属于右值。此时两个重载都能匹配:const boost::any&:可以绑定右值临时对象;boost::any&&:也可以绑定右值临时对象。
根据C++重载解析规则,绑定到右值引用的重载比绑定到const左值引用的重载优先级更高,因此编译器最终选择了右值版本。
解决方案
如果你想让左值std::shared_ptr匹配const boost::any&版本,可采用以下两种方式:
方式1:显式构造boost::any左值
int main() { std::shared_ptr<MyClass> c_sptr = std::make_shared<MyClass>(); boost::any any_obj(c_sptr); // 显式构造左值boost::any MyClass::DumpMyClass(any_obj); // 匹配const boost::any&版本 MyClass::DumpMyClass(std::move(c_sptr)); // 匹配boost::any&&版本 return 0; }
方式2:增加模板重载转发
为std::shared_ptr单独提供重载,显式控制boost::any的构造方式:
class MyClass { // 原有代码... public: static void DumpMyClass(const std::shared_ptr<MyClass>& obj) { // 构造左值boost::any,转发到const&版本 DumpMyClass(boost::any(obj)); } static void DumpMyClass(std::shared_ptr<MyClass>&& obj) { // 构造右值boost::any,转发到&&版本 DumpMyClass(boost::any(std::move(obj))); } static void DumpMyClass(boost::any&& my_class_obj) { std::cout << "rvalue reference" << std::endl; } static void DumpMyClass(const boost::any& my_class_obj) { std::cout << "lvalue reference" << std::endl; } };
内容的提问来源于stack exchange,提问作者Abhineet Pandey
相关产品推荐
相关产品推荐

