我很困惑,在对代码进行了一些重构之后,下面的代码不再起作用,因为它跳转到auto, auto
的情况而忽略了Complex, Complex
的情况。我承认我不太了解overload在做什么[[exactly,但是对我来说,这两个代码看起来完全一样,只是一个代码直接获取其参数,而另一个代码定义了参数在功能主体本身中。
Math_Node Function_Manager::add(const Math_Node& arg){
Math_Object obj1 = arg.children_ptr()->at(0)->data();
Math_Object obj2 = arg.children_ptr()->at(1)->data();
if( std::holds_alternative<Complex>(obj1) ){
std::cerr << "obj1 is complex\n";
}
if( std::holds_alternative<Complex>(obj2) ){
std::cerr << "obj2 is complex\n";
}
return std::visit(overload{
[](const Complex& a, const Complex& b) -> Math_Object{
std::cerr << "COMPLEX ADD_\n";
return add_(a, b);
}
, [](const Matrix& a, const Matrix& b) -> Math_Object{
std::cerr << "MATRIX ADD_\n";
return add_(a, b);
}
, [&arg](auto& a, auto& b) -> Math_Node{
std::cerr << "NOT FOUND\n";
return arg;
}
}, obj1, obj2);
}
代码打印
obj1 is complex obj2 is complex NOT FOUND
这是重构前的工作代码:
Math_Object Function_Manager::add(const Math_Object& arg0, const Math_Object& arg1){ return std::visit( overload{ [](const Complex& a, const Complex& b) -> Math_Object{ return add_(a, b); } , [](const Matrix& a, const Matrix& b) -> Math_Object{ return add_(a, b); } , [](auto& a, auto& b) -> Math_Object{ throw std::runtime_error( ("Unsupported arguments for add: " + to_string(a) + to_string(b)).c_str()); } }, arg0, arg1 ); }
我唯一想出的是obj1
和obj2
并不是真正想要的类型,但是std::cerr
的印刷证明了它们是正确的。那么为什么std :: visit不能这样识别它,并且我该如何解决?
obj1
和obj2
不符合const
的资格。在第二个示例中,arg0
和arg1
是。
[overload
只是对分配给它的所有lambda的调用运算符进行重载解析(假定它是通常的实现)。
auto&
/ auto&
比obj1
/ obj2
更适合const Complex&
/ const Complex&
,因为后者需要资格转换以添加const
,而auto&
/ auto&
可以推导为Complex&
/ Complex&
,而无需资格转换。arg0
/ arg1
是const
,所以auto&
/ auto&
的模板参数推导将产生const Complex&
/ const Complex&
,并且此调用均不会也不会直接采用const Complex&
/ const Complex&
的人进行任何转换。如果两个函数的调用转换顺序相同,则该调用将通过一些其他标准来消除歧义,其中之一是非模板函数优于模板函数。直接使用const Complex&
/ const Complex&
的重载不是模板(因为它不是通用lambda),因此是首选。
const auto&
/ const auto&
代替auto&
/ auto&
。