brace-enclosed initializer list conversion error

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

Answer

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