使用运算符()从代理类返回unique_ptr成员变量



我想创建一个包装类(在这种情况下是非空检查,但也可以是其他检查(。

是否有任何方法可以通过operator()提取成员变量,从而可以移出成员变量。用例是std::unique_ptr<>

这是的用例

#include <memory>
struct S {
int x = 0;
S(int x): x(x) {}
};
template <typename Type>
class NotNull
{
public:
NotNull(Type value): m_value(std::move(value)) {}
operator Type&() // <--------------------------------- this is the question
{
assertIsNotNull();
return m_value;
}

typename std::pointer_traits<Type>::element_type *get() {
return m_value.get();
}
private:
void assertIsNotNull() {}
Type m_value;
};

这就是需要工作的地方

// Test code
int main() {
{
NotNull<S *> x {new S{10}};
auto y = x; // This works
delete y;
}
{
NotNull<std::shared_ptr<S>> x{std::make_shared<S>(10)};
auto y = x; // This works
}

{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
S* y = x.get(); // This does work, and needs to work as expected
// that is _not_ move the member
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
auto y = std::move(x); // This copies the whole class
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
std::unique_ptr<S> y = std::move(x); // <----------------- This does not work
}
}

编译器似乎不明白我想在std::move调用中转换为unique_ptr。

error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = S; _Dp = std::default_delete<S>]'
57 |         std::unique_ptr<S> y = std::move(x); 
|     

编译器资源管理器链接

是否可以以某种方式使用类作为std::unique_ptr的代理,并获得这种用于移出成员变量的语法。

PS。正如你可能已经猜到的那样,我不能依赖例如gsl::not_null,因为据我所知,那里不存在这个功能。DS.

编译器了解您想要转换为unique_ptr&(即Type&(很好。当您将转换的结果分配给本地unique_ptr对象时,问题就会出现:由于它是一个左值引用,编译器会尝试调用复制构造函数(而不是移动构造函数,它需要一个右值引用(,但由于unique_ptr删除了它的复制构造函数,您会得到错误。

在这一行中,您可能想做的是转换为unique_ptr&amp;(即右值参考(。为此,您可以基于ref限定符重载转换运算符:

operator Type&() & // converts to lvalue ref if invoked on lvalue
{
assertIsNotNull();
return m_value;
}
operator Type&&() && // converts to rvalue ref if invoked on a temporary
{
assertIsNotNull();
return std::move(m_value);
}

通过这种方式,转换运算符将转换为与调用它时相同类型的引用(即,从正常变量中使用的左值,如果在临时或移动的对象上使用,则转换为右值(。

根据对象是左值引用还是右值引用,可以使用引用限定符来创建成员函数的单独版本,如下所示:

#include <memory>
#include <iostream>
struct S {
int x = 0;
S(int x): x(x) {}
};
template <typename Type>
class NotNull
{
public:
NotNull(Type value): m_value(std::move(value)) {}
operator Type&()
{
assertIsNotNull();
return m_value;
}
auto get() &
{
std::cout << "lvalue n";
return m_value.get();
}
auto get() &&
{
std::cout << "rvalue n";
auto retval =  m_value.get();
m_value.release();
return retval;
}
private:
void assertIsNotNull() {}
Type m_value;
};
int main()
{
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
S* y = x.get(); // This does work, and needs to work as expected
// that is _not_ move the member
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
std::unique_ptr<S> y = std::unique_ptr<S>(std::move(x).get());  // Is this what you want?
}
}

最新更新