根据提案n4015实现expected<E, T>。

4
我开始根据提案实现了expected<E, T>,但遇到了问题。在描述单子功能(5.9)时,在绑定时指出,如果结果已经包含在上下文(expected<E, T>)中,则不应再次包装。
我实现的方式是,绑定有两个重载(使用enable_if),一个用于返回expected实例的函子,实现没有在上下文中包装它,另一个用于返回其他类型的函子,它会在上下文中包装它。我遇到了一个问题,非包装版本在调用者中没有值的情况下必须返回一个默认构造的expected<E1, T1>,这给了默认构造的错误值。
这导致返回的expected的进一步连续失去了导致默认构造的错误的上下文。
也许我应该处理被称为is_same<expected<E,T>, functor_ret_type>的上下文,在调用者中出现错误的情况下,我可以转发“this”并保留错误的上下文,但这将导致返回expected<E1, E2>的函子返回expected<E, expected<E1, E2>> 假设该类具有以下特点:
E& error(); //returns the stored error
T& operator*(); //returns a reference to the stored value
bool has_value(); //returns true if the expected value is present, false if the error is present

以下是我最初的实施方式:

这里是我最初的实现方式:

//overload for wrapping functors
template<typename Functor>
auto bind(Functor functor) -> std::enable_if<is_instance<expected, 
                                             decltype(functor(**this))>::value,
                                             decltype(functor(**this))>::type
{
    using result_type = decltype(functor(**this));
    if (this->has_value())
    {
        return functor(**this);
    }
    return result_type();
}


//overload for non wrapping functors
template<typename Functor>
auto bind(Functor functor) -> std::enable_if<!is_instance<expected, 
                                             decltype(functor(**this))>::value,
                                             expected<E, decltype(functor(**this))>>::type
{
    using result_type = decltype(functor(**this));
    if (has_value())
    {
        return { functor(**this) };
    }
    return expected<E, result_type>(this->error());
}

在第一个重载中,如果没有值,我们会返回一个默认构造的expected<E, T>。该类型是functor返回的类型,其中包含一个默认构造的错误类型E,这使得我们由于未调用函数而失去了原始错误的上下文。

如果我将上述行为解释为“如果functor返回与调用绑定的相同类型的expected<E, T>,则不进行封装;否则进行封装”,我们可以有以下实现:

//overload for wrapping functors
template<typename Functor>
auto bind(Functor functor) -> std::enable_if<is_same<expected<E, T>, 
                                             decltype(functor(**this))>::value,
                                             decltype(functor(**this))>::type
{
    if (this->has_value())
    {
        return functor(**this);
    }
    return *this;
}


//overload for non wrapping functors
template<typename Functor>
auto bind(Functor functor) -> std::enable_if<!is_same<expected<E, T>,
                                             decltype(functor(**this))>::value,
                                             expected<E, decltype(functor(**this))>>::type
{
    using result_type = decltype(functor(**this));
    if (has_value())
    {
        return { functor(**this) };
    }
    return expected<E, result_type>(this->error());
}

在这里,如果没有值存在于包装的重载中,我们会转发this,这使得我们能够知道最初的错误是什么,但是如果函数返回expected<E1, T1>,则结果将是被包装的expected<E, expected<E1, T1>>
我可以想到的第三种方法是仅将E视为上下文,这会稍微不那么严格,并允许解开返回expected<E, T1>的函数对象,但对于expected<E1, T1>的问题仍然存在。
哪种方法是正确的?也许还有其他方法我完全没有想到?
谢谢。

n4015 没有 5.9 章节。 - ecatmur
@ikh添加了一个代码示例来说明我的问题,能否重新打开这个问题? - Moshe Magnes
我仍然不明白你指的是哪个部分。你是在阅读 https://isocpp.org/files/papers/n4015.pdf 上的不同版本吗? - ecatmur
1
@ecatmur,我也在想。http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4015.pdf 包含一个5.9节,日期比iso.org上的晚6天。 - Niall
**this 应该做什么? - BЈовић
显示剩余2条评论
1个回答

1
"

bind是基于unwrap定义的:

"
template <class Ex,class F>
’see below’ expected<E,T>::bind(F&& func)

Returns: - if bool(*this) returns unwrap(expected<E, decltype(func(move(val)))>(func(move(val)))), otherwise returns get_unexpected().

https://isocpp.org/files/papers/n4015.pdfhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4015.pdf中,unwrap仅为expected<E, expected<E,U>>提供非平凡的语义;也就是说,两个意外类型E必须相同:

template <class E, class U>
constexpr expected<E,U> expected<E,expected<E,U>>::unwrap() const&;

Returns: - If bool(*this) then **this. else get_unexpected()

如果有两种不同的意外类型E1和E2,则unwrap无效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接