aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-05-20 12:23:58 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-05-20 12:23:58 +0200
commitfd94c6f239d2436b6152935b4c99217129953a5d (patch)
treec9ebef4ec79371ae02d24a9817797baa3447f20b
parent2fc53c801eb551154f0a2aa96522cf3182a65b7a (diff)
Add convert_to_base<T>(value) variants that allow derive-to-base conversion
-rw-r--r--libbuild2/variable.hxx15
-rw-r--r--libbuild2/variable.txx35
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)
{