Can the <double> option be implemented as an 8-byte object?

Is it possible to implement std :: optional so that sizeof(std::optional<double>) == 8 somehow uses that you can store characters in a NAN, see http://en.cppreference.com/ w / cpp / numeric / math / nan ? Are there implementations that do this? Can this be done in terms of functionality available in the standard?

+5
source share
4 answers

I do not think that this can be done, because there is no rule prohibiting the use of programs and relying on additional bits in NaN on their own. Then, if you store the magic number in optional , it looks like it is not present instead of the special NaN application.

+1
source

The answer is multiple.

First of all, it cannot be implemented with the functionality available in the standard, since Standard does not say anything about a floating point implementation.

Secondly, for IEEE 754 floating points, you can implement your own version, specializing in std::optional for doubles. However, this means that you exclude the actual value (NaN is the result obtained by some arithmetic operations) from your range of values. However, diving deep into IEEE 754, you can choose a specific NaN representation (there are many!) As a no-value.

+1
source

It is not possible to implement std::optional like this because it contradicts post-conditions that specify how the class (template) behaves. For example: std::optional contains a value if it is initialized with a value of type T , but your suggested std::optional<double> will not contain a value if it was initialized with a value that is the special NaN value that you selected.

In addition, the C ++ standard does not guarantee / require a floating point type to support (quietly) NaN. Some systems do not.

Of course, it is possible to implement your own custom class optional with different semantics. Of course, then you will rely on the fact of existence of NaN values ​​determined by the implementation. You should also rely on knowledge of the floating point representation, since, as far as I know, there are no standard applications for checking the NaN payload - only to generate a value that has a specific payload.

+1
source

The implementation of what you offer is pretty trivial, using a good text editor and cut-paste. Since this is a good idea, I decided to add it to my toolbar. My main motivation is that std :: optional <> s is quite large and therefore impractical to use in std :: variant <> types.

 #include <type_traits> #include <limits> #include <exception> class bad_optional_flt_access : public std::exception { public: bad_optional_flt_access() {} const char* what() const noexcept override { return "bad optional float access"; } }; template <typename Float, bool = std::is_floating_point<Float>::value> class optional_flt; template <typename Float> class optional_flt<Float, false> {}; template <typename Float> class optional_flt<Float, true> { public: constexpr optional_flt() noexcept : value_(std::numeric_limits<Float>::quiet_NAN()) {} constexpr optional_flt(const Float& val) noexcept : value_(val) {} template<typename T> constexpr optional_flt(const T& val) noexcept : value_(Float(val)) {} constexpr bool has_value() const noexcept { return value_ != std::numeric_limits<Float>::quiet_NAN(); } void reset() noexcept { value_ = std::numeric_limits<Float>::quiet_NAN(); } constexpr void swap(optional_flt& other) noexcept { std::swap(value_, other.value_); } constexpr operator bool() const noexcept { return has_value(); } Float& value () & { if (!has_value()) throw bad_optional_flt_access(); return value_; } Float&& value () && { if (!has_value()) throw bad_optional_flt_access(); return value_; } constexpr const Float& value () const & { if (!has_value()) throw bad_optional_flt_access(); return value_; } Float& operator * () & noexcept { return value_; } constexpr const Float& operator * () const & noexcept{ return value_; } template< class U > constexpr Float value_or( U&& default_value ) const& { return (has_value()) ? value_ : default_value; } template< class U > constexpr Float value_or( U&& default_value ) && { return (has_value()) ? value_ : default_value; } private: Float value_; }; template< class T, class U > constexpr bool operator==( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() == rhs.value(); } template< class T, class U > constexpr bool operator!=( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() != rhs.value(); } template< class T, class U > constexpr bool operator<( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() < rhs.value(); } template< class T, class U > constexpr bool operator<=( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() <= rhs.value(); } template< class T, class U > constexpr bool operator>( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() > rhs.value(); } template< class T, class U > constexpr bool operator>=( const optional_flt<T>& lhs, const optional_flt<U>& rhs ) { return lhs.value() >= rhs.value(); } template<typename T> constexpr optional_flt<T> make_optional_flt(const T& x) { return optional_flt<T>(x); } int main() { int i = 2; auto x = optional_flt<float>{i}; auto y = optional_flt<double>(2.5); return (*x < .5) ? sizeof(optional_flt<double>) : 1; } 

The above code is gcc -std=c++11 , clang -std=c++14 and cl /std:c++11 compatible.

0
source

Source: https://habr.com/ru/post/1270594/


All Articles