是否可以通过某种方式使用可以在NAN中存储字符的sizeof(std::optional<double>) == 8
来实现std :: optional,请参阅http://en.cppreference.com/w/cpp/numeric/math/nan?是否有实现这样做?是否可以根据标准中提供的功能来完成?
答案 0 :(得分:1)
我不认为这可以做到,因为没有规则阻止程序自己利用和依赖NaN中的额外位。然后,如果您将幻数存储到optional
中,它看起来就不会出现,而不是应用程序的特殊NaN。
答案 1 :(得分:1)
答案是多方面的。
首先,不能使用Standard中提供的功能实现,因为Standard没有提到浮点实现。
其次,对于IEEE 754浮点,您可以通过专门设置std::optional
来实现自己的可选项。但是,这意味着您从值范围中排除有效值(NaN是由某些算术运算产生的结果)。但是,深入了解IEEE 754,您可以选择特定的 NaN表示(其中有很多!)作为无值。
答案 2 :(得分:1)
不可能像这样实现std::optional
,因为它与指定类(模板)行为方式的后置条件相矛盾。例如:std::optional
包含值,如果使用类型T
初始化值,但您建议的std::optional<double>
不会包含如果使用您选择的特殊NaN值初始化值,则为值。
此外,C ++标准不保证/要求浮点类型支持(安静)NaN。有些系统没有。
当然可以用不同的语义实现自己的非标准optional
类。当然,您将依赖NaN值存在的实现定义事实。您还必须依赖浮点表示的知识,因为据我所知,没有用于检查NaN有效负载的标准实用程序 - 仅用于生成具有特定有效负载的值。
答案 3 :(得分:0)
使用优秀的文本编辑器和剪切粘贴来实现您的建议相当简单。由于这是一个好主意,我决定将它添加到我的工具箱中。我的主要动机是std :: optional&lt;&gt; s相当大,因此在std :: variant&lt;&gt;中使用是不实际的。类型。
#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;
}
上面的代码是gcc -std=c++11
,clang -std=c++14
和cl /std:c++11
兼容。