为何C++17中两段相似代码调用函数,一个抛出std::bad_any_cast异常?
问题原因分析
核心原因是函数调用时传递的参数值类别(左值/右值)不同,导致std::function的模板参数推导结果存在差异,最终与std::any中存储的类型匹配情况不同:
1. 先明确存储的基础类型
你存在std::any中的是std::function<std::any(Context*)>,这个函数对象接受的是值传递的Context*参数——对于标量类型(指针属于标量)来说,值传递的参数可以接受左值或右值的指针。
2. compute函数内调用失败的原因
在compute函数中,你传递给method_map的是左值Context*(比如一个命名变量的指针)。此时代码尝试通过std::any_cast获取std::function<std::any(Context*&)>类型的对象:
- 这个目标类型要求参数是左值引用类型的
Context*,和std::any中存储的std::function<std::any(Context*)>是完全不同的特化类型。 std::any的any_cast要求目标类型与存储类型严格匹配(或属于可隐式兼容的窄范围类型),这种不同引用修饰的std::function特化不属于兼容范畴,因此触发std::bad_any_cast异常。
3. main函数直接调用成功的原因
在main函数中,你传递的是右值Context*(比如临时创建的指针、或经std::move转换后的指针)。此时代码尝试std::any_cast到std::function<std::any(Context*&&)>:
std::function存在隐式适配规则:当存储的函数参数是值类型T时,它可以被隐式转换为接受T&&(右值引用)的std::function特化类型——因为右值可以被拷贝到值参数中,符合函数调用的语义。- 这种隐式转换被
std::any_cast认可,因此转换成功,函数可以正常执行。
关键知识点补充
std::any存储的是具体的、无歧义的类型实例,any_cast不会自动进行复杂的类型转换,仅支持严格匹配或有限的隐式兼容转换。std::function的不同参数引用修饰(T/T&/T&&)会生成完全不同的特化类型,其中只有T和T&&的特化存在隐式兼容可能,T和T&的特化则完全不兼容。
内容的提问来源于stack exchange,提问作者scengka
相关产品推荐
相关产品推荐

