C++ constructor with optional parameters

Viewed 1825

Hi I am new to C++ and I am trying to create a class hierarchy where each class represents a node in a schema document, think json-schema. Have a look at the representation of e.g. a string. A string can have three optional constraints

  • min_length
  • max_length
  • pattern

Furthermore a string is a type so it would make sense to have a base class representing a type from which all types (boolean, number, ...) inherit. Now, one way to achieve this is by writing something like

struct Type {
  const std::string m_name;

  Type(const std::string& name)
  : m_name{name}
  {}

  virtual X Serialize() const {
    //...
  }
};

struct String : Type {
  const int m_max_len;
  const int m_min_len;
  const std::string m_pattern;

  String(int min_len, int max_len, const std::string& pattern)
  : Type("string")
  , m_min_len(min_len)
  , m_max_len(max_len)
  , m_pattern(pattern)
  {}

  X Serialize() const override {
    // If min_length was not set then it should be omitted from the serialized output.
  }
};

This String implementation would not make the constraints optional. What to do?

Options:

  • One could employ a strategy where the default constructor parameters where set to some "illegal" value like INT_MIN (which would work in this case because the length can not be negative) but that would not work in the general case. It could very well be that all possible integers a legal values, the same goes for the pattern parameter.
  • You do not want to have different constructors for every possible permutation of optional parameters. In this case there are three optional values which would yield 2^3 different constructors. Also it would not be possible for the compiler to distinguish between the constructors String(int min_length) and String(int max_length).
  • It would be possible to do something like

    String(int* min_length = nullptr, int* max_length = nullptr, const std::string* nullptr)

    but then you would have to use new/delete or give lvalues for the set parameters.
  • Finally each member could be a std::unique_ptr.

    String(std::unique_ptr<int> min_value nullptr, std::unique_ptr<int> max_value = nullptr, std::unique_ptr<const std::string> pattern = nullptr)

    but then you would end up with quite complicated calls when creating an instance of String. Also if implementing a container of Types which may have optional parameters of its own things quickly get out of hand.

Finally, the code must be compatible with C++14.

4 Answers

You can simply use std::optional:

String(const std::optional<int> &min_len, const std::optional<int> &max_len, 
       const std::optional<std::string> &pattern);

Type *type = new String(5, {}, std::nullptr); // last 2 parameters are omitted.

For C++14 you can use similar constructs that exist in other open source libraries, (e.g. boost::optional, folly::Optional).

I lack reputation points to comment on @Kostas

To be compatible with C++14 you can try experimental namespace which has optional (if it is available/works on your compiler)

#include <experimental/optional>

then you can use

String(std::experimental::optional<int> &min_len,.....)
min_len.value_or(-1)

You can write your own class that can contain value or not if you can't use std::optional. It is not like lot of code. Can make its interface like std::optioal has or can make something different, what matters is data:

class OptInt {
    bool set_;
    int value_;
public:
    OptInt() : set_(false) , value_(0) {}
    OptInt(int v) : set_(true), value_(v) {}
    // can add other ways how to create it

    bool isSet() const {return set_;}
    int get() const {if (!set_) throw 666; return value_;}
    // can add other operations you want to it.
};

Then you can use such default-constructed OptInt as your default argument and so it will be not set, but if caller provides int argument then it will be set.

Have you tried to use an std::optional (since C++17)? I know you mentioned the need to use C++14 compatible code, but there is a boost::optional available.

Related