可选的<double>可以实现为8字节对象吗?

时间:2017-08-04 15:39:41

标签: c++ std optional boost-optional

是否可以通过某种方式使用可以在NAN中存储字符的sizeof(std::optional<double>) == 8来实现std :: optional,请参阅http://en.cppreference.com/w/cpp/numeric/math/nan?是否有实现这样做?是否可以根据标准中提供的功能来完成?

4 个答案:

答案 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++11clang -std=c++14cl /std:c++11兼容。