-2

I have a yaml-cpp which always converts into a std::string, and sometimes also into something else. For example, if the string actually is "3.14", it would also convert into double. I'd first like to try int, then double, then bool, and if that doesn't work, convert to a std::string. Alright, so let's nest those try-catches:

try {
  const int a = node.as<int>();
  std::cout << "int!" << a << std::endl;
} catch (YAML::BadConversion) {
  try {
    const double a = node.as<double>();
    std::cout << "double!" << a << std::endl;
  } catch (YAML::BadConversion) {
    try {
      const bool a = node.as<bool>();
      std::cout << "bool!" << a << std::endl;
    } catch (YAML::BadConversion) {
      const std::string a = node.as<std::string>();
      std::cout << "string!" << a << std::endl;
    }
  }
}

Hm, the deeper and deeper nesting tells me that this isn't the best way to write that code.

Any suggestions on how to improve the design here? Flat nesting would certainly be advised.

Nico Schlömer
  • 53,797
  • 27
  • 201
  • 249
  • Not sure but just one try {} and catch(...)? Then check Exception through a function...Like ExceptionStatement(Exception e). – Omid CompSCI Aug 03 '16 at 21:13

3 Answers3

4

You may put it in a function like:

template<typename N, typename T>
bool tryParseNode(N& node, T& val) {
  try {
    val = node.as<T>();
    return true;
  } catch (YAML::BadConversion) {
    return false;
  }  
}

then:

int a;
double d;
bool b;
std::string s;
if (tryParseNode(node, a) {
  std::cout << "int!" << a << std::endl;
}
else if (tryParseNode(node, d) {
  std::cout << "double!" << d << std::endl;
}
else if (tryParseNode(node, b) {
  std::cout << "bool!" << b << std::endl;
}
else if (tryParseNode(node, s) {
  std::cout << "string!" << s << std::endl;
}
marcinj
  • 48,511
  • 9
  • 79
  • 100
2

Try the other way round:
Convert into to a string, then try bool, etc.
Everything within a single try-catch and ignore the exception.

Robert Kock
  • 5,795
  • 1
  • 12
  • 20
1

Using exceptions for normal control flow is considered bad practice. In this case, the as method uses the `YAML::convert::decode' method to attempt to convert the node into the requested type returning a false if it fails instead of throwing an exception.

int anInt;
double aDouble;
bool aBool;

if (YAML::convert <int>::decode (node, anInt))
  std::cout << "int!" << anInt << std::endl;
else
if (YAML::convert <double>::decode (node, aDouble))
    std::cout << "double!" << aDouble << std::endl;
else
if (YAML::convert <bool>::decode (node, aBool))
    std::cout << "double!" << aBool << std::endl;
else
    std::cout << "string!" << node.as <std::string> () << std::endl;

which could be further simplified to

template <typename value_type>
std::optional <value_type> decode (YAML::Node const & Node)
{
    value_type Value;

    if (YAML::convert <value_type>::decode (node, Value))
        return  { Value };
    else
        return {};
}

if (auto anInt = decode <int> (node))
  std::cout << "int!" << *anInt << std::endl;
else
if (auto aDouble = decode <double> (node))
    std::cout << "double!" << *aDouble << std::endl;
else
if (auto aBool = decode <bool> (node))
    std::cout << "double!" << *aBool << std::endl;
else
    std::cout << "string!" << node.as <std::string> () << std::endl;
nate
  • 1,771
  • 12
  • 17