考虑this 。有一个不可复制、不可移动的类,并且为其定义了一些谓词:
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; }
};
因为有保证copy/move-elision在 C++17 中我们可以有:
auto getA() { return AA(10); }
问题是:如何定义 getGoodA
,在返回 good
时转发 getA
,否则抛出异常?这可能吗?
auto getGoodA()
{
auto got = getA();
if (got.good()) return got; // FAILS! Move is needed.
throw std::runtime_error("BAD");
}
最佳答案
如果我们在 C++20 中进行契约检查,您就可以编写如下内容:
auto getGoodA(int i) [[post aa: aa.good()]] {
return getA(i);
}
(至少我这么认为 - 我并不完全清楚 aa
返回伪变量的类型;它需要是对返回位置中返回对象的引用。 )不幸的是契约(Contract)是 removed from C++20所以我们还需要一段时间才能写这篇文章。
假设您无法修改 getA
,目前唯一的方法是从 getGoodA
返回一个包装类。显而易见的解决方案是unique_ptr,但我们实际上不需要执行堆分配;延迟构造包装器将 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**){}; }};
}
这里我给了 BB
一个引用风格的接口(interface),允许你写 AA& aa = getGoodA(i)
,但你同样可以给它一个指针 -样式接口(interface)(operator*
和 operator->
),甚至复制 AA
的接口(interface)。
关于c++ - 通过检查复制/移动省略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62334793/