【问题标题】:std::visit does not recognise typesstd::visit 不识别类型
【发布时间】:2020-02-20 17:32:12
【问题描述】:

我很困惑,经过一些代码重构后,以下代码不再起作用,因为它跳转到 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
                          );
    }

我唯一能想到的是obj1obj2 并不是真正需要的类型,但打印到std::cerr 证明它们是。那么为什么 std::visit 无法识别它,我该如何解决?

【问题讨论】:

  • auto&amp; 优先于 T const&amp; 用于非常量 T。尝试将auto&amp; 更改为auto const&amp;
  • 然后我得到一个无效的转换错误。
  • @infinitezero 您能否将该错误消息添加到您的问题中?我不明白为什么会有错误。
  • 太长了。 Math_Object 是一个包含 Complex 的 std::variant。 Math_Node 是一个模板化节点,其中模板设置为 Math_Object。通过将 lambda 的返回类型更改为 Math_Node 而不是返回 Math_Object(它隐式调用 Math_Node 构造函数),我摆脱了错误消息。

标签: c++ lambda generic-lambda std-variant


【解决方案1】:

在您的第一个示例中,obj1obj2 不是 const 合格的。

在您的第二个示例中,arg0arg1 是。

overload 只是对所有给它的 lambdas 的调用运算符进行重载解析(假设它是通常的实现)。


在第一个示例的重载解析中,auto&amp;/auto&amp;const Complex&amp;/const Complex&amp; 更适合 obj1/obj2,因为后者需要进行限定转换才能添加 @987654333 @,而auto&amp;/auto&amp;可以推导出为Complex&amp;/Complex&amp;,不需要进行限定转换。


在第二个例子中不是这样,因为arg0/arg1const,所以auto&amp;/auto&amp; 的模板参数推导将产生const Complex&amp;/const Complex&amp; 而这也不是直接拨打const Complex&amp;/const Complex&amp;的电话也不需要任何转换。

如果两个函数在一次调用中具有同样良好的转换顺序,则该调用通过一些附加条件来消除歧义,其中之一是非模板函数优于模板函数。直接采用const Complex&amp;/const Complex&amp; 的重载不是模板(因为它不是通用的 lambda),因此是首选。


要解决此问题,只需在所有调用中使用相同的限定条件,即在最后一次调用中使用 const auto&amp;/const auto&amp; 而不是 auto&amp;/auto&amp; 或通过传递 @987654353 重现第二个示例的重载解析行为@ 和 std::as_const(obj2) 而不是 obj1obj2std::visit

【讨论】:

  • 哦,哇,是的,现在看起来很明显。谢谢。起初我遇到了一个无效的转换错误,我可以通过显式转换来修复!
  • @infinitezero 我不确定该错误是什么以及为什么需要在任何地方进行强制转换。您可以将其添加到您的问题中吗?您可以通过std::as_constobj1obj2 传递给std::visit,而不是显式转换或更改auto 参数,以获得第二个示例行为。我看不出这里有任何强制转换的理由,而且显式强制转换往往很危险,特别是如果他们强制转换 const away
猜你喜欢
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多