1

I have the following old code that used to work on "older" combinations/versions of C++, QuantLib and Boost. While was playing around with the idea of upgrading to newer versions ie C++11, QuantLib >= 1.76, boost >= 1_71 building now throws the following "conversion" error(s).
I am using [options] 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>

I did pick up some comments on brace lists and having to have the "right" C++ version to be able to cope with these but my C++ is not good enough to pick up on what exactly the problem could be in (this is my opinion/best guess) of which part of the code is acting "funny" now, causing the problems.

  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());
  }

ending up being used here ...

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

...

So my question would be - is there an elegant or quick way of fixing the code with respect to handling these <brace-enclosed initializer list>() "conversions"?
Like I said these are all "greek to me" so I would appreciate any hints of how to apply quick fixes to such (think I saw somewhere just additional set of {} curly braces being added)? And also feel free to correct me if I am on the wrong path regarding the error source here?
Thanks

GWD
  • 1,387
  • 10
  • 22
  • Please make a [mre] – cigien Sep 29 '21 at 17:03
  • That is sadly beyond what I am able to fit in here (a SO question) ... I know I would usually try to reduce it to a reprex but the code base is a behemoth and I am way to unfamiliar with 1. the code (I inherited) and 2. () conversions That is why I was hoping to find someone on SO that is more acquainted with these and their conversions, which seem to have become stricter lately? To pick up some tips. – GWD Sep 29 '21 at 17:11
  • From what I can tell from the error messages, it looks like you have a value (property) missing from your `params` initializer list, as the type `transformationType` is trying to be assigned to is the same as the previous value `greensAlgorithm`. – 1201ProgramAlarm Sep 29 '21 at 17:19
  • The beauty of a [mre] (MRE) is that it's SMALL. Take your code and back it up. Then bit-by-bit rip out everything that's not needed to reproduce the problem. Often you can get the MRE down to a few lines of code. The true beauty of the MRE is that you rarely need to get that far. Typically as you reduce the noise from the other code around the mistake the mistake becomes obvious, so you stop and fix the bug. If you get down to a point where you can't remove anything without also removing the error, you edit the question and paste in what you have left. – user4581301 Sep 29 '21 at 17:19
  • If you build the MRE early in the question-asking process odds are very good that you'll never have to hit the post button. – user4581301 Sep 29 '21 at 17:22
  • @ all the repex tips -> I know that this would be the preferable way, but again - as I mentioned I am not at all familiar with `` so I would not even know where to start building a reprex in that direction? That's why I am more curious where a pre C11 (working) code could break in a C11 world. Code used to work about 5 years ago with an "older" toolset. I was thinking to give it a shot if someone has had some (similar) experience and could point me to some "small" code adaptation to catch this (new) type of error. – GWD Sep 29 '21 at 17:35

1 Answers1

1

The errors are narrowing conversions, which are never allowed in uniform initializers.

That's relevant because aggregate initialization existed all along and did not have that restriction. Now in C++11 world, aggregate initialization is just a form of uniform initialization, with ditto narrowing rules.

You should explicitly convert the respective values (checking that the conversion is safe!)

E.g.

struct X { short i; };

int init = 42;
X x{init}; // not ok

Explicitly converting makes it ok:

X x{static_cast<short>(init)}; // ok
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I know it is a lot to ask but can you point/show me to a (single) example conversion of a value in my code above? Do you think that (my guess) explicitly converting "schemeDesc" is sufficient or also the other ones? – GWD Sep 29 '21 at 20:15
  • 1
    That's a lot to ask (seeing that you have a lot of dependencies and unshown code). The good news is: the compiler is already telling you exactly which ones. You can take them one by one - no need to guess (although anticipating may increase your speed). Also, note that if you're invoking regular constructors, simply using `()` syntax instead of `{}` syntax make the narrowing behaviour back to the old rules. – sehe Sep 29 '21 at 21:03