Search code examples
c++compiler-errorsoption-typevariantstd-variant

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

The code is roughly:

#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;
}

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.


Solution

  • 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.