This situation is related to How to make a constraint on the parameters of the constructor, but it's slightly different.
You want to initialize a non-default-constructible member but need to check for constraints before constructing it.
Example:
(Please note that this is really just an example. Whether one should use unsigned integers instead in this specific situation is discussable, but the question really is about the general case where you want to check in constructors)
You have the following class:
class Buffer {
public:
Buffer() = delete;
Buffer(int size) noexcept;
};
....
class RenderTarget {
public:
....
private:
int width_, height_;
Buffer surface_;
};
The constructor has to check the integer arguments for validness:
RenderTarget::RenderTarget(int width, int height) :
width_(width), height_(height),
surface_(width_*height)
{
if (width_<0 || height_<0)
throw std::logic_error("Crizzle id boom shackalack");
}
Note how Buffer does not have a default constructor, and the real constructor is noexcept, i.e. there is no way to catch an error.
When the integer arguments are negative, one has a hosed surface_ already. It would be nicer to do the constraint checking before using the constrained value. Is it possible?
Named Constructor
You can use a so called Named Constructor (see also https://isocpp.org/wiki/faq/ctors#named-ctor-idiom), and make the constructor
private:Named Constructors are interesting in case you have multiple constructors that may be ambiguous to use, e.g. Temperature <-- Celsius | Fahrenheit | Kelvin or Distance <-- Meter | Yard | Cubit | Kilometers | ....
Otherwise, (personal opinion) they impose an unexpected abstraction and also distraction and should be avoided.
Ternary Operator and
throwC++ allows in [expr.cond] the use of
throw-expressions in one or both operands to the ternary operator (?:-operator):If you do not store the arguments, you can also use
?:inside an expression, of course:Or you combine the precondition-checking into a single operand:
Using the
?:-operator with athrow-expression inline can be very nice for basic constraint checking and avoids having to fall back to using a default constructor (if any), and then doing "real initialization" within the constructor body.This can become a bit unwieldy for more complex scenarios.
Static Private Member
The best of both worlds can be used, of course:
... or you write static functions for any member you need to precondition-check:
This is nice because you have the complete C++-machinery at hand for constraint checking, and for example can easily add logging. It scales well, but is a bit less handy for simple scenarios.