【问题标题】:C++ compiler error: use of deleted function std::variant()C++ 编译器错误:使用已删除的函数 std::variant()
【发布时间】:2021-12-28 20:22:21
【问题描述】:

我不断收到以下错误消息,告诉我正在使用已删除的函数,我认为这是 std::variant 默认构造函数。

In file included from main.cpp:2:
Document.hpp: In instantiation of ‘Document<StateVariant, EventVariant, Transitions>::Document(StateVariant&&) [with StateVariant = std::variant<DraftState, PublishState>; EventVariant = std::variant<EventWrite, EventRead>; Transitions = TransitionRegister]’:
main.cpp:7:61:   required from here
Document.hpp:33:37: error: use of deleted function ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’
   33 |    Document(StateVariant &&a_state) {
      |                                     ^
In file included from Document.hpp:6,
                 from main.cpp:2:
/usr/include/c++/11/variant:1385:7: note: ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’ is implicitly deleted because the default definition would be ill-formed:
 1385 |       variant() = default;
      |       ^~~~~~~
/usr/include/c++/11/variant:1385:7: error: use of deleted function ‘constexpr std::_Enable_default_constructor<false, _Tag>::_Enable_default_constructor() [with _Tag = std::variant<DraftState, PublishState>]’
In file included from /usr/include/c++/11/variant:38,
                 from Document.hpp:6,
                 from main.cpp:2:
/usr/include/c++/11/bits/enable_special_members.h:112:15: note: declared here
  112 |     constexpr _Enable_default_constructor() noexcept = delete;
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~

代码大致如下:

#include <iostream>
#include <variant>
class DraftState {
public:
   DraftState() = default; // default constructor
   DraftState(const DraftState &a_state) { m_msg = a_state.m_msg; } // copy constructor
   DraftState(const std::string &a_rMsg = "") { m_msg = a_rMsg; } // custom constructor
   DraftState(DraftState &&a_state) { m_msg = std::move(a_state.m_msg);} // move constructor
   DraftState& operator=(DraftState &&a_state) { if(this != &a_state) { m_msg = std::move(a_state.m_msg); } return *this; } // move assignable constructor

   ~DraftState() = default; // destructor
   std::string getState() { return "DraftState"; }
   std::string m_msg;
};

class PublishState{
   // similar to DraftState
};

using State = std::variant<DraftState, PublishState>;

template<typename StateVariant>
class Document
{
public:
   Document() = default;
   Document(StateVariant &&a_state) {
      m_state = std::move(a_state);
   }
   StateVariant m_state;
//...
};

int main()
{
   DraftState draftState("draft");
   Document<State> doc(draftState);
   return 0;
}

我尝试在自定义构造函数 Document(StateVariant &&a_state) 的初始化列表中添加一个默认构造函数调用,但这似乎也不起作用。感谢您对理解这条神秘信息的任何帮助。抱歉,代码太长了。

【问题讨论】:

  • 请出示minimal reproducible example(关注最小)
  • 说到,这里有一个更简单的例子:godbolt.org/z/7szrYdWMe 注意x 的定义不能编译,但y 可以。除非您强制x 构造代表B,否则它将与列表中的第一个A 一起使用,并且A 不能默认构造。没有A,没有variant
  • 现在为什么我没有写答案?
  • 是的,这似乎是一个有趣的情况。谢谢。

标签: c++ compiler-errors optional variant std-variant


【解决方案1】:

虽然您确实需要处理一个最小示例,但核心问题是您的 DraftState 默认构造函数与带有默认参数的字符串构造函数不明确。见https://godbolt.org/z/hTnsjoWaW

为了默认可构造,std::variant 要求第一个类型参数默认可构造。歧义导致编译器认为您的类不是默认可构造的,因此变体也不是。

此外,您的 Document 移动构造函数应该使用成员初始化列表,而不是赋值。而且您的 DraftState 缺少复制赋值运算符,但除非有更多内容,否则我不会明确定义所有复制/移动/析构函数值。请参阅Rule of Five

【讨论】:

  • 我认为你成功了。似乎问题出在默认字符串 arg 上,我并不真正需要它。真的只是学到了很多,所以我做了一百万个构造函数。我可以清理代码。
  • 关于构造函数,在这里做移动语义有意义吗?如果这些最终成为非常大的对象,我是否可以节省机器上的空间/时间?
  • @Coder909 一般来说,除非一个类对需要直接释放的资源执行操作,例如新建/删除操作,否则它应该使用编译器生成的默认复制/移动操作。此 SO 链接 stackoverflow.com/questions/4172722/what-is-the-rule-of-three/… 提供了更多详细信息。
猜你喜欢
  • 2017-12-04
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2015-10-25
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多