diff --git a/include/vectorwrapper/vectorwrapper.hpp b/include/vectorwrapper/vectorwrapper.hpp index dcef69c..93e11be 100644 --- a/include/vectorwrapper/vectorwrapper.hpp +++ b/include/vectorwrapper/vectorwrapper.hpp @@ -134,6 +134,22 @@ namespace vwr { enum { value = true }; }; + template struct get_wrapped_ifn { + typedef V type; + }; + template struct get_wrapped_ifn> { + typedef T type; + }; + + template + struct directly_convertible { + enum { + value = + not HasGetAtMethod::type>>::value and + not HasGetAtMethod::type>>::value + }; + }; + template class VecBase { friend Vec& assign_same_type ( Vec& parLeft, const Vec& parRight ); @@ -160,9 +176,14 @@ namespace vwr { const vector_type& data ( void ) const { return m_wrapped; } template - const typename std::enable_if::value, V2>::type& cast ( void ) const; + const typename std::enable_if::value and directly_convertible::value, V2>::type& cast ( void ) const; template - typename std::enable_if::value, V2>::type& cast ( void ); + typename std::enable_if::value and directly_convertible::value, V2>::type& cast ( void ); + + template + const typename std::enable_if::value and not directly_convertible::value, V2>::type& cast ( void ) const; + template + typename std::enable_if::value and not directly_convertible::value, V2>::type& cast ( void ); template VecBase& operator+= ( const VecBase& parOther ); template VecBase& operator-= ( const VecBase& parOther ); @@ -330,6 +351,8 @@ namespace vwr { Vec::type> binary_op ( const Vec& parLeft, const Vec& parRight, Op parOp, const Vec::type>& parLastVal, bt::number_seq ); } //namespace implem + template struct is_castable_to { }; + template class Vec : public implem::VecBase { public: diff --git a/include/vectorwrapper/vectorwrapper.inl b/include/vectorwrapper/vectorwrapper.inl index e6e7e27..88e7dfe 100644 --- a/include/vectorwrapper/vectorwrapper.inl +++ b/include/vectorwrapper/vectorwrapper.inl @@ -83,7 +83,7 @@ namespace vwr { template template - const typename std::enable_if::value, V2>::type& VecBase::cast() const { + auto VecBase::cast() const -> const typename std::enable_if::value and directly_convertible::value, V2>::type& { static_assert(sizeof(V2) <= sizeof(VecBase) - min_offset::value, "V2 must fit in V starting from the first coordinate"); static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); static_assert(min_offset::vector_type>::value == 0, "V2 must not have any properties before the first coordinate"); @@ -103,7 +103,32 @@ namespace vwr { template template - typename std::enable_if::value, V2>::type& VecBase::cast() { + auto VecBase::cast() -> typename std::enable_if::value and directly_convertible::value, V2>::type& { + return const_cast(const_cast*>(this)->cast()); + } + + template + template + auto VecBase::cast() const -> const typename std::enable_if::value and not directly_convertible::value, V2>::type& { + static_assert(std::is_standard_layout::value, "V2 must be a standard layout type"); + typedef typename is_vec::vector_type v2_type; + static_assert(std::is_base_of::vector_type>, VectorWrapperInfo>::value, "Casting for this type has to be explicitly enabled"); + + //Assert that V2 won't stomp on part of V's data, unless the user + //has explicitly said he doesn't care. + static_assert((sizeof(typename VectorWrapperInfo::vector_type>::scalar_type) * VectorWrapperInfo::vector_type>::dimensions == sizeof(V2)) or + IsCastIgnoreTrailingPropertiesSet::vector_type>::value, + "V2 must not have any properties past the last coordinate"); + static_assert(alignof(typename VectorWrapperInfo::scalar_type) == alignof(V2), "Casting to V2 would give you a misaligned variable"); + + return *reinterpret_cast( + reinterpret_cast(&(*this)[0]) + ); + } + + template + template + auto VecBase::cast() -> typename std::enable_if::value and not directly_convertible::value, V2>::type& { return const_cast(const_cast*>(this)->cast()); }