This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
system_category() and error_code::error_code() should be constexprSection: 19.5.3.5 [syserr.errcat.objects], 19.5.4.2 [syserr.errcode.constructors] Status: NAD Submitter: Peter Dimov Opened: 2017-06-27 Last modified: 2017-07-12
Priority: Not Prioritized
View all other issues in [syserr.errcat.objects].
View all issues with NAD status.
Discussion:
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.
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());
[2017-07 Toronto Tuesday PM issue prioritization]
NAD; This is a feature request; needs a paper.
Proposed resolution:
This wording is relative to N4659.
Edit 19.5.3.1 [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;
};
const error_category& generic_category() noexcept;
const error_category& system_category() noexcept;
Edit 19.5.3.5 [syserr.errcat.objects] as indicated:
const error_category& generic_category() noexcept;[…]
const error_category& system_category() noexcept;[…]
Edit 19.5.4.1 [syserr.errcode.overview], class error_code synopsis, as indicated:
class error_code {
public:
// 19.5.4.2 [syserr.errcode.constructors], constructors
error_code() noexcept;
error_code(int val, const error_category& cat) noexcept;
template <class ErrorCodeEnum>
error_code(ErrorCodeEnum e) noexcept;
// 19.5.4.3 [syserr.errcode.modifiers], modifiers
void assign(int val, const error_category& cat) noexcept;
template <class ErrorCodeEnum>
error_code& operator=(ErrorCodeEnum e) noexcept;
void clear() noexcept;
// 19.5.4.4 [syserr.errcode.observers], observers
int value() const noexcept;
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
};
Edit 19.5.4.2 [syserr.errcode.constructors] as indicated:
error_code() noexcept;[…]
error_code(int val, const error_category& cat) noexcept;[…]
Edit 19.5.4.3 [syserr.errcode.modifiers] as indicated:
void assign(int val, const error_category& cat) noexcept;[…]
void clear() noexcept;[…]
Edit 19.5.4.4 [syserr.errcode.observers] as indicated:
int value() const noexcept;[…]
const error_category& category() const noexcept;[…]