Title
system_category() and error_code::error_code() should be constexpr
Status
nad
Section
[syserr.errcat.objects][syserr.errcode.constructors]
Submitter
Peter Dimov

Created on 2017-06-27.00:00:00 last changed 90 months ago

Messages

Date: 2017-07-12.01:58:24

Proposed resolution:

This wording is relative to N4659.

  1. Edit [syserr.errcat.overview], class error_category synopsis, as indicated:

    class error_category {
    public:
      constexpr error_category() noexcept;
      virtual ~error_category();
      error_category(const error_category&) = delete;
      error_category& operator=(const error_category&) = delete;
      virtual const char* name() const noexcept = 0;
      virtual error_condition default_error_condition(int ev) const noexcept;
      virtual bool equivalent(int code, const error_condition& condition) const noexcept;
      virtual bool equivalent(const error_code& code, int condition) const noexcept;
      virtual string message(int ev) const = 0;
    
      bool operator==(const error_category& rhs) const noexcept;
      bool operator!=(const error_category& rhs) const noexcept;
      bool operator<(const error_category& rhs) const noexcept;
    };
    
    constexpr const error_category& generic_category() noexcept;
    constexpr const error_category& system_category() noexcept;
    
  2. Edit [syserr.errcat.objects] as indicated:

    constexpr const error_category& generic_category() noexcept;
    

    […]

    constexpr const error_category& system_category() noexcept;
    

    […]

  3. Edit [syserr.errcode.overview], class error_code synopsis, as indicated:

    class error_code {
    public:
      // [syserr.errcode.constructors], constructors
      constexpr error_code() noexcept;
      constexpr error_code(int val, const error_category& cat) noexcept;
      template <class ErrorCodeEnum>
      error_code(ErrorCodeEnum e) noexcept;
      
      // [syserr.errcode.modifiers], modifiers
      constexpr void assign(int val, const error_category& cat) noexcept;
      template <class ErrorCodeEnum>
      error_code& operator=(ErrorCodeEnum e) noexcept;
      constexpr void clear() noexcept;
      
      // [syserr.errcode.observers], observers
      constexpr int value() const noexcept;
      constexpr const error_category& category() const noexcept;
      error_condition default_error_condition() const noexcept;
      string message() const;
      explicit operator bool() const noexcept;
      
    private:
      int val_; // exposition only
      const error_category* cat_; // exposition only
    };
  4. Edit [syserr.errcode.constructors] as indicated:

    constexpr error_code() noexcept;
    

    […]

    constexpr error_code(int val, const error_category& cat) noexcept;
    

    […]

  5. Edit [syserr.errcode.modifiers] as indicated:

    constexpr void assign(int val, const error_category& cat) noexcept;
    

    […]

    constexpr void clear() noexcept;
    

    […]

  6. Edit [syserr.errcode.observers] as indicated:

    constexpr int value() const noexcept;
    

    […]

    constexpr const error_category& category() const noexcept;
    

    […]

Date: 2017-07-12.01:58:24

[ 2017-07 Toronto Tuesday PM issue prioritization ]

NAD; This is a feature request; needs a paper.

Date: 2017-06-27.00:00:00

The default constructor of error_code should be constexpr to enable constant initialization; as a practical matter, there are reports that it regularly shows up in profiles because clearing error codes is so frequent.

Suggested resolution:

  • add constexpr to the declaration of system_category() in [syserr.errcat.overview] and [syserr.errcat.objects];

  • optionally, add constexpr to the declaration of generic_category() in the same two sections;

  • add constexpr to the default constructor of error_code in [syserr.errcode.overview] and [syserr.errcode.constructors];

  • optionally, add constexpr to the error_code(int val, const error_category& cat) constructor in the same two sections;

  • optionally, add constexpr to error_code::assign;

  • optionally, add constexpr to error_code::clear;

  • optionally, add constexpr to error_code::value;

  • optionally, add constexpr to error_code::category.

There was an objection that system_category() can't be made constexpr because it needs to "immortalize" the object so that it's not destroyed at process shutdown or module unload, in order for the error_code facility to remain usable. However, the following proof of concept shows how to achieve this and still make the function constexpr:

#include <new>

template<class _Ty>
  union _Immortalizer
  { // constructs _Ty, never destroys
  constexpr _Immortalizer(): __ty()
  {
  }

  ~_Immortalizer() noexcept {}
  _Immortalizer(const _Immortalizer&) = delete;
  _Immortalizer& operator=(const _Immortalizer&) = delete;

  _Ty __ty;
};

struct error_category
{
  virtual ~error_category() = default;
};

struct system_category_impl : public error_category
{
};

[[clang::require_constant_initialization]] static const _Immortalizer<system_category_impl> _System_category;

constexpr error_category const& system_category() noexcept
{
  return _System_category.__ty;
}

struct error_code
{
  int val_;
  const error_category* cat_;

  constexpr error_code() noexcept : val_(0), cat_(&system_category()) {}

  constexpr int value() const noexcept { return val_; }
  constexpr error_category const& category() const noexcept { return *cat_; }
};

constexpr error_code s_code;

static_assert(s_code.value() == 0);
static_assert(&s_code.category() == &system_category());
History
Date User Action Args
2017-07-12 01:58:24adminsetmessages: + msg9355
2017-07-12 01:58:24adminsetstatus: new -> nad
2017-06-28 17:06:31adminsetmessages: + msg9308
2017-06-27 00:00:00admincreate