子类化时编译错误 std::optional
Compile error while subclassing std::optional
我正在尝试在 MS C++17 (VS2017) 中使用 subclass std::optional 将消息字段添加到 class,但出现编译错误
error C2280: 'OptMsg<bool>::OptMsg(const OptMsg<bool> &)
': attempting to reference a deleted function
Intellisense 提供更多洞察力:
function "OptMsg<T>::OptMsg(const OptMsg<bool> &) throw() [with T=bool]
" (declared implicitly) cannot be referenced -- it is a deleted function
这告诉我编译器对引用已删除函数的复制构造函数有问题抛出?我从函数中得到错误 return 一个实例。例如,
OptMsg<bool> foo()
{
OptMsg<bool> res = false;
return res; // <-- Getting compile error here
}
这是我的 class。任何见解表示赞赏!
template <class T>
class KB_MAPPING_ENGINE_API OptMsg : public std::optional<T>
{
public:
constexpr OptMsg() noexcept
: optional{}
{}
constexpr OptMsg(std::nullopt_t) noexcept
: optional{}
{}
constexpr OptMsg(const T & other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
constexpr explicit OptMsg(const T && other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
OptMsg & operator = ( const OptMsg & other ) noexcept
{
if ( &other != this )
m_Message = other.m_Message;
return *this;
}
OptMsg && operator = ( const OptMsg && other )
{
if ( &other != this )
m_Message = other.m_Message;
return *this;
}
void SetMessage( const std::string & message ) { m_Message = message; }
std::string GetMessage() { return m_Message; }
private:
std::string m_Message;
};
我发现了一些问题,例如:
constexpr explicit OptMsg(const T && other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
我相信你的意思是
constexpr explicit OptMsg( OptMsg&& other) noexcept
: optional<T>{std::forward<OptMsg>(other)}
, m_Message{other.m_Message}
{}
这里有两点说明:
移动不是恒定的!原始数据可能会被修改以识别数据的所有权已被移动!
您必须使用 std::forward
将右值引用转发给基础 class 移动构造函数。
还有你的:
std::string GetMessage() const { return m_Message; }
必须标记 const
!
下一件事:
constexpr OptMsg( const T& value ): OptMsg::optional{ value }{}
不能标记为explicit
,因为它专用于从bool->OptMsg
做类型转换
Which tells me the compiler has in issue with my copy constructor
referencing the deleted function throw?
不,没有功能throw()
。这种表示法是 pre-C++11 声明函数不抛出任何东西的方式。现在推荐noexcept
,但显然,微软还没有赶上......
相反,错误告诉您您正在尝试调用复制构造函数(在您标记的行中),但是您的 class 没有!
为什么没有?这里
constexpr OptMsg(const T & other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
看起来它打算成为复制构造函数。但是,并不是因为参数是const T&
。复制构造函数需要 const OptMsg&
.
通常,复制构造函数会自动为您声明。这并没有发生在这里,因为您明确声明了 operator=(const OptMsg&)
。因此,错误消息提到您的复制构造函数是 "deleted function".
如何解决?
要么正确声明复制构造函数,要么删除赋值运算符。编译器将为您生成一个。
但请注意,您当前的赋值运算符(复制和移动)实现仅分配消息而不分配 optional
本身。这是故意的吗?将是一个非常意外的行为......如果这是有意的,你必须自己声明一切(但正确!)。
但假设这不是预期的,并且进一步假设您的复制操作应该只是平凡地复制整个实例(消息 + 基数 class),那么自动生成的构造函数和赋值运算符将完全按照您的要求进行,不需要自己写。但是,您可以将其写入您的 class,让每个人立即看到您正在使用编译器生成的:
constexpr OptMsg() = default;
constexpr OptMsg(const OptMsg & other) = default;
constexpr OptMsg(OptMsg && other) = default;
OptMsg & operator = ( const OptMsg & other ) = default;
OptMsg & operator = ( OptMsg && other ) = default;
更新:
请注意,移动构造函数和移动赋值运算符需要 OptMsg&&
作为参数。你一直有 const OptMsg&&
。因此你的错误信息
"operator =(const OptMsg &&)': is not a special member function which can be defaulted
另请参阅 the rule of zero(感谢@Caleth)。
我正在尝试在 MS C++17 (VS2017) 中使用 subclass std::optional 将消息字段添加到 class,但出现编译错误
error C2280: '
OptMsg<bool>::OptMsg(const OptMsg<bool> &)
': attempting to reference a deleted function
Intellisense 提供更多洞察力:
function "
OptMsg<T>::OptMsg(const OptMsg<bool> &) throw() [with T=bool]
" (declared implicitly) cannot be referenced -- it is a deleted function
这告诉我编译器对引用已删除函数的复制构造函数有问题抛出?我从函数中得到错误 return 一个实例。例如,
OptMsg<bool> foo()
{
OptMsg<bool> res = false;
return res; // <-- Getting compile error here
}
这是我的 class。任何见解表示赞赏!
template <class T>
class KB_MAPPING_ENGINE_API OptMsg : public std::optional<T>
{
public:
constexpr OptMsg() noexcept
: optional{}
{}
constexpr OptMsg(std::nullopt_t) noexcept
: optional{}
{}
constexpr OptMsg(const T & other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
constexpr explicit OptMsg(const T && other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
OptMsg & operator = ( const OptMsg & other ) noexcept
{
if ( &other != this )
m_Message = other.m_Message;
return *this;
}
OptMsg && operator = ( const OptMsg && other )
{
if ( &other != this )
m_Message = other.m_Message;
return *this;
}
void SetMessage( const std::string & message ) { m_Message = message; }
std::string GetMessage() { return m_Message; }
private:
std::string m_Message;
};
我发现了一些问题,例如:
constexpr explicit OptMsg(const T && other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
我相信你的意思是
constexpr explicit OptMsg( OptMsg&& other) noexcept
: optional<T>{std::forward<OptMsg>(other)}
, m_Message{other.m_Message}
{}
这里有两点说明:
移动不是恒定的!原始数据可能会被修改以识别数据的所有权已被移动!
您必须使用 std::forward
将右值引用转发给基础 class 移动构造函数。
还有你的:
std::string GetMessage() const { return m_Message; }
必须标记 const
!
下一件事:
constexpr OptMsg( const T& value ): OptMsg::optional{ value }{}
不能标记为explicit
,因为它专用于从bool->OptMsg
Which tells me the compiler has in issue with my copy constructor referencing the deleted function throw?
不,没有功能throw()
。这种表示法是 pre-C++11 声明函数不抛出任何东西的方式。现在推荐noexcept
,但显然,微软还没有赶上......
相反,错误告诉您您正在尝试调用复制构造函数(在您标记的行中),但是您的 class 没有!
为什么没有?这里
constexpr OptMsg(const T & other) noexcept
: optional<T>{other}
, m_Message{other.m_Message}
{}
看起来它打算成为复制构造函数。但是,并不是因为参数是const T&
。复制构造函数需要 const OptMsg&
.
通常,复制构造函数会自动为您声明。这并没有发生在这里,因为您明确声明了 operator=(const OptMsg&)
。因此,错误消息提到您的复制构造函数是 "deleted function".
如何解决?
要么正确声明复制构造函数,要么删除赋值运算符。编译器将为您生成一个。
但请注意,您当前的赋值运算符(复制和移动)实现仅分配消息而不分配 optional
本身。这是故意的吗?将是一个非常意外的行为......如果这是有意的,你必须自己声明一切(但正确!)。
但假设这不是预期的,并且进一步假设您的复制操作应该只是平凡地复制整个实例(消息 + 基数 class),那么自动生成的构造函数和赋值运算符将完全按照您的要求进行,不需要自己写。但是,您可以将其写入您的 class,让每个人立即看到您正在使用编译器生成的:
constexpr OptMsg() = default;
constexpr OptMsg(const OptMsg & other) = default;
constexpr OptMsg(OptMsg && other) = default;
OptMsg & operator = ( const OptMsg & other ) = default;
OptMsg & operator = ( OptMsg && other ) = default;
更新:
请注意,移动构造函数和移动赋值运算符需要 OptMsg&&
作为参数。你一直有 const OptMsg&&
。因此你的错误信息
"operator =(const OptMsg &&)': is not a special member function which can be defaulted
另请参阅 the rule of zero(感谢@Caleth)。