2

考虑一下。有一个不可复制、不可移动的类,并且为它定义了一些谓词:

struct AA
{
    AA(AA const&  otehr) = delete;
    AA(AA      && otehr) = delete;
    AA& operator = (AA const&  otehr) = delete;
    AA& operator = (AA      && otehr) = delete;

    AA(int something) { }

    bool good() const { return false; }
};

由于C++17中保证复制/移动省略,我们可以拥有:

auto getA() { return AA(10); }

问题是:如何定义,如果它返回getGoodA则将转发,否则将抛出异常?有可能吗?getAgood

auto getGoodA()
{
    auto got = getA();
    if (got.good()) return got; // FAILS! Move is needed.
    throw std::runtime_error("BAD");
}
4

1 回答 1

2

如果我们在 C++20 中进行了合同检查,您将能够编写如下内容:

auto getGoodA(int i) [[post aa: aa.good()]] {
    return getA(i);
}

(至少我是这么认为的——我对aa返回伪变量的类型并不完全清楚;它需要是对返回位置中返回对象的引用。)不幸的是,合同已从 C++20中删除,所以我们还需要一段时间才能写出这篇文章。

假设您无法修改getA,目前唯一的方法是从getGoodA. 显而易见的解决方案是unique_ptr,但我们实际上不需要执行堆分配;延迟构造的包装器也可以

#include <cstddef>
#include <new>
struct BB {
    alignas(AA) std::byte buf[sizeof(AA)];
    template<class F, class G> BB(F f, G g) { g(*new (buf) AA{f()}); }
    BB(BB&&) = delete;
    ~BB() { reinterpret_cast<AA&>(buf).~AA(); }
    operator AA&() { return reinterpret_cast<AA&>(buf); }
    operator AA const&() const { return reinterpret_cast<AA const&>(buf); }
};
auto getGoodA(int i) {
    return BB{
        [&] { return getA(i); },
        [&](AA& aa) { if (!aa.good()) throw (struct bad**){}; }};
}

这里我给出BB了一个引用样式的接口,允许你写AA& aa = getGoodA(i),但你同样可以给它一个指针样式的接口(operator*operator->),甚至复制AA.

于 2020-06-12T00:29:36.313 回答