std::visit 不识别类型
std::visit does not recognise types
我很困惑,经过一些代码重构后,以下代码不再有效,因为它跳转到 auto, auto
案例并忽略了 Complex, Complex
案例。诚然,我不太明白 overload 究竟 在做什么,但对我来说,这两个代码看起来完全一样,除了一个例外,一个直接获取它的参数而另一个具有在函数体本身中定义的参数。
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&
比 const Complex&
/[=20= 更适合 obj1
/obj2
],因为后者需要限定转换加上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&
或重现第二个示例的重载解析行为通过将 std::as_const(obj1)
和 std::as_const(obj2)
而不是 obj1
和 obj2
传递给 std::visit
.
我很困惑,经过一些代码重构后,以下代码不再有效,因为它跳转到 auto, auto
案例并忽略了 Complex, Complex
案例。诚然,我不太明白 overload 究竟 在做什么,但对我来说,这两个代码看起来完全一样,除了一个例外,一个直接获取它的参数而另一个具有在函数体本身中定义的参数。
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&
比 const Complex&
/[=20= 更适合 obj1
/obj2
],因为后者需要限定转换加上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&
或重现第二个示例的重载解析行为通过将 std::as_const(obj1)
和 std::as_const(obj2)
而不是 obj1
和 obj2
传递给 std::visit
.