@@ -81,13 +81,40 @@ class Property
8181 Property ();
8282
8383 // / base class for Property exceptions
84- class error ;
84+ class error : public std ::runtime_error
85+ {
86+ protected:
87+ std::string property_name_;
88+ std::string msg_;
89+
90+ public:
91+ explicit error (const std::string& msg);
92+ const std::string& name () const { return property_name_; }
93+ void setName (const std::string& name);
94+ const char * what () const noexcept override { return msg_.c_str (); }
95+ };
96+
8597 // / exception thrown when accessing an undeclared property
86- class undeclared ;
98+ class undeclared : public Property ::error
99+ {
100+ public:
101+ explicit undeclared (const std::string& name);
102+ };
103+
87104 // / exception thrown when accessing an undefined property
88- class undefined ;
105+ class undefined : public Property ::error
106+ {
107+ public:
108+ explicit undefined ();
109+ explicit undefined (const std::string& name);
110+ };
111+
89112 // / exception thrown when trying to set a value not matching the declared type
90- class type_error ;
113+ class type_error : public Property ::error
114+ {
115+ public:
116+ explicit type_error (const std::string& current_type, const std::string& declared_type);
117+ };
91118
92119 using SourceFlags = uint;
93120 // / function callback used to initialize property value from another PropertyMap
@@ -101,12 +128,22 @@ class Property
101128 // / reset to default value (which can be empty)
102129 void reset ();
103130
104- // / the current value defined or will the fallback be used ?
105- inline bool defined () const { return !value_.empty (); }
131+ // / is a value defined?
132+ inline bool defined () const { return !( value_.empty () && default_. empty () ); }
106133
107- // / get current value (or default if not defined )
134+ // / get current value (or default if not set )
108135 inline const boost::any& value () const { return value_.empty () ? default_ : value_; }
109136 inline boost::any& value () { return value_.empty () ? default_ : value_; }
137+
138+ // / get typed value of property. Throws bad_any_cast on type mismatch, undefined if !defined().
139+ template <typename T>
140+ inline const T& value () const {
141+ const boost::any& v{ value () };
142+ if (v.empty ())
143+ throw Property::undefined ();
144+ return boost::any_cast<const T&>(value ());
145+ }
146+
110147 // / get default value
111148 const boost::any& defaultValue () const { return default_; }
112149
@@ -142,34 +179,6 @@ class Property
142179 InitializerFunction initializer_;
143180};
144181
145- class Property ::error : public std::runtime_error
146- {
147- protected:
148- std::string property_name_;
149- std::string msg_;
150-
151- public:
152- explicit error (const std::string& msg);
153- const std::string& name () const { return property_name_; }
154- void setName (const std::string& name);
155- const char * what () const noexcept override { return msg_.c_str (); }
156- };
157- class Property ::undeclared : public Property::error
158- {
159- public:
160- explicit undeclared (const std::string& name, const std::string& msg = " undeclared" );
161- };
162- class Property ::undefined : public Property::error
163- {
164- public:
165- explicit undefined (const std::string& name, const std::string& msg = " undefined" );
166- };
167- class Property ::type_error : public Property::error
168- {
169- public:
170- explicit type_error (const std::string& current_type, const std::string& declared_type);
171- };
172-
173182// hasSerialize<T>::value provides a true/false constexpr depending on whether operator<< is supported.
174183// This uses SFINAE, extracted from https://jguegant.github.io/blogs/tech/sfinae-introduction.html
175184template <typename T, typename = std::ostream&>
@@ -318,19 +327,15 @@ class PropertyMap
318327 // / Get the value of a property. Throws undeclared if unknown name
319328 const boost::any& get (const std::string& name) const ;
320329
321- // / Get typed value of property. Throws undeclared, undefined, or bad_any_cast.
330+ // / Get typed value of property. Throws undeclared or bad_any_cast.
322331 template <typename T>
323332 const T& get (const std::string& name) const {
324- const boost::any& value = get (name);
325- if (value.empty ())
326- throw Property::undefined (name);
327- return boost::any_cast<const T&>(value);
328- }
329- // / get typed value of property, using fallback if undefined. Throws bad_any_cast on type mismatch.
330- template <typename T>
331- const T& get (const std::string& name, const T& fallback) const {
332- const boost::any& value = get (name);
333- return (value.empty ()) ? fallback : boost::any_cast<const T&>(value);
333+ try {
334+ return property (name).value <T>();
335+ } catch (Property::undefined& e) {
336+ e.setName (name);
337+ throw e;
338+ }
334339 }
335340
336341 // / count number of defined properties from given list
0 commit comments