diff --git a/strongdef.hpp b/strongdef.hpp index bd9ca00b..04b01111 100644 --- a/strongdef.hpp +++ b/strongdef.hpp @@ -11,14 +11,19 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2018 Danny Robson */ #ifndef __UTIL_STRONGDEF_HPP #define __UTIL_STRONGDEF_HPP +#include "cast.hpp" +#include "types/traits.hpp" + #include #include +#include + namespace util { /// A transparent wrapper around a (typically lightweight) type for the @@ -32,63 +37,97 @@ namespace util { // TODO: ideally we'd default the constructor, but templated // constructors can't be defaulted? So we just stub one out. template >> - constexpr strongdef () { ; } + constexpr explicit strongdef () { ; } - constexpr strongdef (const T &_data): data (_data) { ; } + constexpr explicit strongdef (util::types::identity_t const &_data): data (_data) { ; } + constexpr strongdef (strongdef const&) = default; - // explicitly disable assignment with unequal types or tags. this - // prevents the converion operator getting invoked and falsely - // allowing assignment with differing types or tags. - template - std::enable_if_t< - !std::is_same::value || !std::is_same::value, - strongdef& - > - operator= (const strongdef &rhs) = delete; - - template - std::enable_if_t< - std::is_same::value && std::is_same::value, - strongdef& - > - operator= (const strongdef &rhs) - { data = rhs.data; return *this; } - - // simple value_type assignment. - strongdef& operator= (const T &rhs)& - { data = rhs; return *this; } + strongdef& operator= (T const &) = delete; + strongdef& operator= (strongdef const &) = default; // conversion operators must not be explicit or it defeats the point // of this class (ease of use, transparency). - operator const T& (void) const& { return data; } - operator T& (void) & { return data; } + explicit operator const T& (void) const& { return data; } + explicit operator T& (void) & { return data; } - auto const& value (void) const { return data; } - auto & value (void) { return data; } + constexpr auto operator== (T const &) = delete; + constexpr auto operator== (strongdef const &rhs) const + { + return data == rhs.data; + } - // explicitly disable equality with unequal types or tags. this - // prevents the conversion operator getting invoked and falsely - // allowing equality with different types or tags. - template - std::enable_if_t< - !std::is_same::value || - !std::is_same::value, - bool - > - operator== (const strongdef &rhs) const = delete; + constexpr auto operator!= (T const&) = delete; + constexpr auto operator!= (strongdef const &rhs) const + { + return data != rhs.data; + } - // provide a usable equality for equal types and tags - template - constexpr - std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool - > - operator== (const strongdef &rhs) const { return data == rhs.data; } + constexpr auto operator< (T const &) const = delete; + constexpr auto operator< (strongdef const &rhs) const { return data < rhs.data; } + + constexpr auto operator> (T const &) const = delete; + constexpr auto operator> (strongdef const &rhs) const { return data > rhs.data; } T data; }; + + + template + std::ostream& + operator<< (std::ostream &os, strongdef const &val) + { + return os << val.data; + } +} + + +template +static auto indices (ContainerT const &obj) +{ + using index_t = typename ContainerT::index_t; + + struct view { + view (ContainerT const &_obj): + m_obj (_obj) + { ; } + + struct iterator { + iterator (index_t _idx): + idx (_idx) + { ; } + + iterator& operator++ () + { + ++idx.data; + return *this; + } + + index_t const& operator* () const { return idx; } + index_t const* operator-> () const { return &idx; } + + bool operator!= (iterator const &rhs) { return idx != rhs.idx; } + + private: + index_t idx; + }; + + iterator begin (void) const { return iterator (index_t (0)); } + iterator end (void) const + { + return index_t ( + util::cast::narrow< + typename index_t::value_type + > ( + m_obj.size () + ) + ); + } + + private: + ContainerT const &m_obj; + }; + + return view {obj}; } diff --git a/test/strongdef.cpp b/test/strongdef.cpp index e7016305..84003344 100644 --- a/test/strongdef.cpp +++ b/test/strongdef.cpp @@ -12,7 +12,7 @@ main (void) // These tests are less about functional testing, and more about link testing. strongdef fortytwo (42u); tap.expect_eq (fortytwo.data, 42u, "raw data equality"); - tap.expect_eq (fortytwo, 42u, "passthrough equality"); + tap.expect_eq (fortytwo, decltype(fortytwo) (42u), "passthrough equality"); // Ensure numeric_limits has been specialised. Unknown types are default initialised, so check if we get non-zero for maximum. tap.expect_eq (std::numeric_limits::max (),