简体   繁体   中英

Copy/move elision with a check

Consider this . There is a non-copyable, non-movable class, and there is some predicated defined for it:

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; }
};

Because of guaranteed copy/move-elision in C++17 we can have:

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

The question is: how can one define getGoodA , that will forward getA in case it returned good and will throw an exception otherwise? Is it possible at all?

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

If we had got contract checking in C++20 you would have been able to write something like:

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

(At least I think so - I'm not entirely clear on the type of the aa return pseudo-variable; it would need to be a reference to the returned object in its return location.) Unfortunately contracts were removed from C++20 so it'll be some time before we can write this.

Assuming you can't modify getA , the only way for now is to return a wrapper class from getGoodA . The obvious solution would be unique_ptr , but we don't actually need to perform heap allocation; a delayed-construction wrapper will do just as well :

#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**){}; }};
}

Here I've given BB a reference-style interface, allowing you to write AA& aa = getGoodA(i) , but you could equally give it a pointer-style interface ( operator* and operator-> ) or even copy the interface of AA .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM