2022-07-15

How to efficiently initialize a std::variant data member in a class template

Consider the following class template, that can hold either a value of type T or an instance of some ErrorInfo class, using a std::variant data member:

template <typename T>
class ValueOrError
{
  private:
    std::variant<T, ErrorInfo> m_var;
};

How can I efficiently initialize the variant T alternative?

I can initialize it with a constructor like this:

template <typename T>
class ValueOrError
{
  public:
    explicit ValueOrError(const T& val) 
      : m_var{val} {}

    …
};

But what syntax/coding technique can I use to enable move semantics optimization during initialization?

If I define a constructor taking a T&&, should I std::move or std::forward the parameter into the m_var?

template <typename T>
class ValueOrError
{
  public:
    // Efficient initialization with move semantics 
    explicit ValueOrError(T&& val)
      : m_var{ /* ?? */ } {}

    …
};

Note on interactions with ErrorInfo constructor overload

The ValueOrError template should also have a constructor overload that takes an ErrorInfo and initializes the variant member accordingly:

template <typename T>
class ValueOrError
{
  public:
    // Initialize with error code instead of T
    explicit ValueOrError(const ErrorInfo& error) 
      : m_var{error} {}

    …
};

It’s important that the generic T constructor overload interacts properly with the specific ErrorInfo overload.

ErrorInfo is a tiny class that wraps an error code (e.g. a simple integer), and can be constructed from such error code:

class ErrorInfo
{
  public:

    explicit ErrorInfo(int errorCode) 
      : m_errorCode{errorCode} 
    {}

    int ErrorCode() const 
    {
        return m_errorCode;
    }

    // … other convenient methods 
    // (e.g. get an error message, etc.)

  private:
    int m_errorCode;
};


No comments:

Post a Comment