简体   繁体   中英

C++ compiler error: use of deleted function std::variant()

I am continually getting the following error message telling me that I am using a deleted function, which I think is the std::variant default constructor.

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;
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~

In my main.cpp file I have:

#include <iostream>
#include "Document.hpp"

int main()
{
   DraftState draftState("draft");
   Document<State, Event, TransitionRegister> doc(draftState);
   doc.write("Hello World!");
   doc.read();
   return 0;
}

In my Document.hpp:

#ifndef DOCUMENT_HPP
#define DOCUMENT_HPP

#include <iostream>
#include <memory>
#include <variant>
#include <optional>
#include "State.hpp"
#include "Event.hpp"

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

struct TransitionRegister {
   std::optional<State> operator()(DraftState &a_rState, const EventWrite &e) {
      std::cout << a_rState.getState() << std::endl;
      return std::optional<State>(PublishState(e.m_msg));
   }

   std::optional<State> operator()(PublishState &a_rState, const  EventRead &e) {
      std::cout << a_rState.getState() << std::endl;
      std::cout << "Message: " << a_rState.m_msg << std::endl;
      return std::nullopt;
   }
};

template<typename StateVariant, typename EventVariant, typename Transitions>
class Document
{
public:
   Document() {}
   Document(StateVariant &&a_state) {
      m_state = std::move(a_state);
   }
   ~Document() = default;

   void write(std::string writing); // for draft state
   void read();    // for publish state, print out.

   void putText(std::string a_text) { m_text = a_text; }
   std::string getText() { return m_text; }
   void dispatch(const Event &Event);

private:
   std::string m_text;
   StateVariant m_state;
};
#endif // DOCUMENT_HPP

In my Document.cpp:

#include <iostream>
#include <optional>
#include <variant>
#include "Document.hpp"

template<typename StateVariant, typename EventVariant, typename Transitions>
void Document<StateVariant, EventVariant, Transitions>::dispatch(const Event &Event)
{
   std::optional<State> new_state = std::visit(TransitionRegister{}, m_state, Event);
   if( new_state ) {
      m_state = *std::move( new_state );
   }
}

template<typename StateVariant, typename EventVariant, typename Transitions>
void Document<StateVariant, EventVariant, Transitions>::write(std::string writing) {
    dispatch(EventWrite(writing));
} // for draft state

template<typename StateVariant, typename EventVariant, typename Transitions>
void Document<StateVariant, EventVariant, Transitions>::read() {
   dispatch(EventRead());
} // for publish state, print out.

In my State.hpp:

#ifndef STATE_HPP
#define STATE_HPP

#include <iostream>

class DraftState {
public:
   DraftState() {}; // 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 = a_state.m_msg; a_state.m_msg = ""; } // move constructor
   DraftState& operator=(DraftState &&a_state) { if(this != &a_state) { m_msg = a_state.m_msg; a_state.m_msg = ""; } return *this; } // move assignable constructor

   ~DraftState() {} // destructor
   std::string getState() { return "DraftState"; }
   std::string m_msg;
};
/*
class ReviewState {

};
*/
class PublishState {
public:
   PublishState() {};
   PublishState(const PublishState &a_state) { m_msg = a_state.m_msg; }
   PublishState(const std::string &a_rMsg) { m_msg = a_rMsg; }
   PublishState(PublishState &&a_state) { m_msg = a_state.m_msg; a_state.m_msg = ""; }
   PublishState& operator=(PublishState &&a_state) { if(this != &a_state) { m_msg = a_state.m_msg; a_state.m_msg = ""; } return *this;}

   ~PublishState() {}
   std::string getState() { return "PublishState"; }
   std::string m_msg;
};
#endif // STATE_HPP

In my Event.hpp:

#ifndef EVENT_HPP
#define EVENT_HPP

#include <iostream>

class EventWrite {
public:
   EventWrite(const std::string &a_rMsg) { m_msg = a_rMsg; }
   ~EventWrite() { }
   std::string m_msg;
};

class EventRead {
public:
   EventRead() {}
   ~EventRead() {}
};

#endif // EVENT_HPP

I have tried adding a default constructor call in the custom constructor Document(StateVariant &&a_state)'s initializer list but that does not seem to work either. Any help understanding this cryptic message is appreciated thanks. Sorry for the long code.

While you do need to work on a minimal example, the core problem is your DraftState default constructor is ambiguous with your string constructor with a default argument. See https://godbolt.org/z/hTnsjoWaW

To be default constructible, std::variant requires the first type argument to be default constructible. The ambiguity causes the compiler to think your class is not default constructible, and therefore neither is the variant.

Also, your move constructor for Document should use the member initializer list, rather than assignment. And your DraftState is missing the copy assignment operator, though unless there's more to it, I wouldn't explicitly define all of the copy/move/destructor values. See the Rule of Five .

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