大括号括起来的初始值设定项列表转换错误

Posted

技术标签:

【中文标题】大括号括起来的初始值设定项列表转换错误【英文标题】:brace-enclosed initializer list conversion error 【发布时间】:2021-11-21 14:40:36 【问题描述】:

我有以下旧代码,这些旧代码用于处理 C++、QuantLib 和 Boost 的“旧”组合/版本。 在考虑升级到新版本(即 C++11)时,QuantLib >= 1.76,boost >= 1_71 构建现在会引发以下“转换”错误。 我正在使用 [选项] g++ -std=gnu++11

hestonslvmodule.cpp:456:7: warning: narrowing conversion of ‘(QuantLib::FdmHestonGreensFct::Algorithm)greensAlgorithm’ from ‘Quant
Lib::FdmHestonGreensFct::Algorithm’ to ‘QuantLib::Real’ aka ‘double’ [-Wnarrowing]
  456 |       greensAlgorithm,
      |       ^~~~~~~~~~~~~~~
hestonslvmodule.cpp:457:7: error: cannot convert ‘const QuantLib::FdmSquareRootFwdOp::TransformationType’ to ‘const QuantLib::FdmH
estonGreensFct::Algorithm’ in initialization
  457 |       transformationType,
      |       ^~~~~~~~~~~~~~~~~~
      |       |
      |       const QuantLib::FdmSquareRootFwdOp::TransformationType
hestonslvmodule.cpp:458:7: error: cannot convert ‘const QuantLib::FdmSchemeDesc’ to ‘const QuantLib::FdmSquareRootFwdOp::Transform
ationType’ in initialization
  458 |       schemeDesc
      |       ^~~~~~~~~~
      |       |
      |       const QuantLib::FdmSchemeDesc
hestonslvmodule.cpp:459:5: error: could not convert ‘<brace-enclosed initializer list>()’ from ‘<brace-enclosed initializer list>’
 to ‘const QuantLib::FdmSchemeDesc’
  459 |     ;
      |     ^
      |     |
      |     <brace-enclosed initializer list>

我确实在大括号列表中找到了一些 cmets,并且必须拥有“正确”的 C++ 版本才能应对这些问题,但我的 C++ 还不足以了解问题可能出在哪里(这是我的意见/最佳猜测)代码的哪一部分现在表现得“有趣”,导致了问题。

  FdmSchemeDesc getFdmSchemeDesc(const std::string& schemeDescStr) 
    return  (schemeDescStr == "ModifiedCraigSneyd") ? FdmSchemeDesc::ModifiedCraigSneyd()
          : (schemeDescStr == "CraigSneyd") ? FdmSchemeDesc::CraigSneyd()
          : (schemeDescStr == "Hundsdorfer") ? FdmSchemeDesc::Hundsdorfer()
          : (schemeDescStr == "ModifiedHundsdorfer") ? FdmSchemeDesc::ModifiedHundsdorfer()
          : (schemeDescStr == "ImplicitEuler") ? FdmSchemeDesc::ImplicitEuler()
          : (schemeDescStr == "ExplicitEuler") ? FdmSchemeDesc::ExplicitEuler()
          : (schemeDescStr == "Douglas") ? FdmSchemeDesc::Douglas()
          : (stop("unknown scheme type"), FdmSchemeDesc::ExplicitEuler());
  

在这里被使用...

class HestonSLVFDMModel 
public:
  HestonSLVFDMModel(QuantLib::Date referenceDate,
                    QuantLib::Date maxDate,
                    Function localVol,
                    S4 hestonProcess,
                    S4 fdmParams) 
    if (!fdmParams.is("HestonSLVFDMParams"))
      stop("Last parameter needs to be of type HestonSLVFDMParams");

    const std::string greensAlgoStr
      = as<std::string>(fdmParams.slot("greensAlgorithm"));

    const FdmHestonGreensFct::Algorithm greensAlgorithm =
        (greensAlgoStr == "Gaussian") ? FdmHestonGreensFct::Gaussian
      : (greensAlgoStr == "ZeroCorrelation") ? FdmHestonGreensFct::ZeroCorrelation
      : (greensAlgoStr == "SemiAnalytical") ? FdmHestonGreensFct::SemiAnalytical
      : (stop("unknown Greens function type"), FdmHestonGreensFct::SemiAnalytical);

    const std::string trafoTypeStr
      = as<std::string>(fdmParams.slot("transformationType"));

    const FdmSquareRootFwdOp::TransformationType transformationType =
        (trafoTypeStr == "Plain") ? FdmSquareRootFwdOp::Plain
      : (trafoTypeStr == "Power") ? FdmSquareRootFwdOp::Power
      : (trafoTypeStr == "Log") ? FdmSquareRootFwdOp::Log
      : (stop("unknown transformation type"), FdmSquareRootFwdOp::Log);

    const std::string schemeDescStr
      = as<std::string>(fdmParams.slot("fdmSchemeType"));

    const FdmSchemeDesc schemeDesc = getFdmSchemeDesc(schemeDescStr);

    const HestonSLVFokkerPlanckFdmParams params = 
      as<unsigned>(fdmParams.slot("xGrid")),
      as<unsigned>(fdmParams.slot("vGrid")),
      as<unsigned>(fdmParams.slot("tMaxStepsPerYear")),
      as<unsigned>(fdmParams.slot("tMinStepsPerYear")),
      as<Real>(fdmParams.slot("tStepNumberDecay")),
      as<unsigned>(fdmParams.slot("predictionCorrectionSteps")),
      as<Real>(fdmParams.slot("x0Density")),
      as<Real>(fdmParams.slot("localVolEpsProb")),
      as<unsigned>(fdmParams.slot("maxIntegrationIterations")),
      as<Real>(fdmParams.slot("vLowerEps")),
      as<Real>(fdmParams.slot("vUpperEps")),
      as<Real>(fdmParams.slot("vMin")),
      as<Real>(fdmParams.slot("v0Density")),
      as<Real>(fdmParams.slot("vLowerBoundDensity")),
      as<Real>(fdmParams.slot("vUpperBoundDensity")),
      as<Real>(fdmParams.slot("leverageFctPropEps")),
      greensAlgorithm,
      transformationType,
      schemeDesc
    ; // THIS IS LINE 459

...

所以我的问题是——在处理这些&lt;brace-enclosed initializer list&gt;()“转换”方面是否有一种优雅或快速的方法来修复代码? 就像我说的那样,这些都是“对我来说是希腊语”,所以我会很感激任何关于如何对其应用快速修复的提示(我想我在某处看到了额外的一组 大括号被添加)?如果我在此处的错误源方面走错了路,还可以随时纠正我吗? 谢谢

【问题讨论】:

请发minimal reproducible example 可悲的是,这超出了我在这里所能适应的范围(一个 SO 问题)......我知道我通常会尝试将其减少为 reprex,但代码库是一个庞然大物,我是不熟悉 1. 代码(我继承)和 2. () 转换的方式这就是为什么我希望在 SO 上找到更熟悉这些及其转换的人,这似乎有最近越来越严格了?获取一些提示。 从我从错误消息中可以看出,您的 params 初始化器列表中缺少一个值(属性),因为类型 transformationType 试图分配给与之前的值greensAlgorithm 相同。 minimal reproducible example (MRE) 的美妙之处在于它很小。获取您的代码并备份它。然后一点一点地去掉重现问题所不需要的一切。通常,您可以将 MRE 简化为几行代码。 MRE 的真正美妙之处在于您很少需要走那么远。通常,当您减少错误周围其他代码的噪音时,错误会变得很明显,因此您停止并修复错误。如果您遇到无法删除任何内容而不删除错误的地步,请编辑问题并粘贴您剩下的内容。 如果您在提问过程的早期构建 MRE,那么您将永远不必点击发布按钮。 【参考方案1】:

错误是缩小转换,这在统一初始化程序中是不允许的。

这是相关的,因为聚合初始化一直存在并且没有那个限制。现在在 C++11 世界中,聚合初始化只是统一初始化的一种形式,还有缩窄规则。

您应该显式转换相应的值(检查转换是否安全!)

例如

struct X  short i; ;

int init = 42;
X xinit; // not ok

显式转换就可以了:

X xstatic_cast<short>(init); // ok

【讨论】:

我知道有很多问题要问,但是您能否指出/显示我上面代码中值的(单个)示例转换?您认为(我的猜测)显式转换“schemeDesc”就足够了,还是其他的? 有很多问题要问(看到您有很多依赖项和未显示的代码)。好消息是:编译器已经准确地告诉你哪些。您可以一一拿下——无需猜测(尽管预测可能会提高您的速度)。另外,请注意,如果您正在调用常规构造函数,只需使用 () 语法而不是 语法会使缩小行为回到旧规则。

以上是关于大括号括起来的初始值设定项列表转换错误的主要内容,如果未能解决你的问题,请参考以下文章

大括号初始值设定项列表中是不是允许显式转换运算符?

无法从大括号括起来的初始化列表转换

为啥在使用大括号初始值设定项列表时首选 std::initializer_list 构造函数?

类大括号括起来的初始化列表失败

C++ 不能用初始值设定项列表初始化非聚合错误

从朋友类继承时无法使用大括号括起来的初始化列表