diff options
-rw-r--r-- | libbuild2/variable.hxx | 15 | ||||
-rw-r--r-- | libbuild2/variable.txx | 35 |
2 files changed, 46 insertions, 4 deletions
diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index aed3350..6dfbbc6 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -92,6 +92,9 @@ namespace build2 // static_cast to const T*. If it is NULL, then cast data_ directly. Note // that this function is used for both const and non-const values. // + // @@ This is currently ignored by as<T>() which is now used in quite a + // few places (in particular, grep for as<T>). + // const void* (*const cast) (const value&, const value_type*); // If NULL, then the types are compared as PODs using memcmp(). @@ -702,14 +705,18 @@ namespace build2 template <typename T> T convert (names&&); // Convert value to T. If value is already of type T, then simply cast it. - // Otherwise call convert(names) above. If value is NULL, then throw - // invalid_argument (with an appropriate message). + // Otherwise call convert(names) above. If the value is NULL, then throw + // invalid_argument (with an appropriate message). See also + // convert_to_base() below. // template <typename T> T convert (value&&); + template <typename T> T convert (const value&); - // As above but preserving the value. + // As above but also allow the derived-to-base conversions (where T is + // base). Note that this call may potentially slice the value. // - template <typename T> T convert (const value&); + template <typename T> T convert_to_base (value&&); + template <typename T> T convert_to_base (const value&); // Default implementations of the dtor/copy_ctor/copy_assing callbacks for // types that are stored directly in value::data_ and the provide all the diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 0b831e9..a1ee340 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -38,6 +38,11 @@ namespace build2 { if (v.type == nullptr) return convert<T> (move (v).as<names> ()); + // + // Note that while it may be tempting to use is_a() here like in cast(), + // the implications are unclear (i.e., we may end up relaxing things we + // don't want to). So we have the convert_to_base() variants instead. + // else if (v.type == &value_traits<T>::value_type) return move (v).as<T> (); } @@ -61,6 +66,36 @@ namespace build2 } template <typename T> + T + convert_to_base (value&& v) + { + if (v) + { + if (v.type == nullptr) + return convert<T> (move (v).as<names> ()); + else if (v.type->is_a<T> ()) + return move (v).as<T> (); + } + + convert_throw (v ? v.type : nullptr, value_traits<T>::value_type); + } + + template <typename T> + T + convert_to_base (const value& v) + { + if (v) + { + if (v.type == nullptr) + return convert<T> (names (v.as<names> ())); + else if (v.type->is_a<T> ()) + return v.as<T> (); + } + + convert_throw (v ? v.type : nullptr, value_traits<T>::value_type); + } + + template <typename T> void default_dtor (value& v) { |