I am working with a C library that uses the usual C "inheritance" trick
typedef struct Base_ *BasePointer;
struct Base_ {
};
typedef struct Derived_ *DerivedPointer;
struct Derived_ {
Base_ header;
};
#define BaseCast(obj) ((BasePointer)(obj))
void bar(BasePointer);
void foo(DerivedPointer derived)
{
bar(BaseCast(derived));
}
I am writing some C utilities and one such utility is a safer BaseCast()
using type traits to check that the object is indeed derived. This BaseCast()
must be completely interchangeable with the macro. I have the following but can this be done better?
// convertible_to_base checks for existence of object->header
// and that object->header is of type Base_
template <typename T>
[[nodiscard]] static inline constexpr BasePointer& BaseCast(T& object) noexcept
{
static_assert(util::convertible_to_base<T>::value, "");
return reinterpret_cast<BasePointer&>(object);
}
template <typename T>
[[nodiscard]] static inline constexpr const BasePointer& BaseCast(const T& object) noexcept
{
static_assert(util::convertible_to_base<T>::value, "");
return reinterpret_cast<const BasePointer&>(object);
}
I don't like the reinterpret_cast()
, but I could not get this to work any other way.
CodePudding user response:
Post this as answer because discussion in comments got stuck somehow and I don't see why it is not an alternative. Return the pointer by value:
template <typename T>
[[nodiscard]] static inline constexpr BasePointer BaseCast(const T& object) noexcept
{
static_assert(util::convertible_to_base<T>::value, "");
return &object.header;
}
As you mentioned, the reference would be a reference to a temporary, hence the non-const ref would be of little use anyhow.