std::error_category not extensible?

We have a reasonably large body of code using std::error_category subclasses on Visual C++. With libc++, error_category::error_category() is private, preventing this code from porting. Was there a late decision by the standards committee to redact system_error extensibility...?

— Gordon

class _LIBCPP_VISIBLE error_category
{
public:
    virtual ~error_category() _NOEXCEPT;

private:
    error_category() _NOEXCEPT;
    error_category(const error_category&);// = delete;
    error_category& operator=(const error_category&);// = delete;

public:
    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;

    _LIBCPP_ALWAYS_INLINE
    bool operator==(const error_category& __rhs) const _NOEXCEPT {return this == &__rhs;}

    _LIBCPP_ALWAYS_INLINE
    bool operator!=(const error_category& __rhs) const _NOEXCEPT {return !(*this == __rhs);}

    _LIBCPP_ALWAYS_INLINE
    bool operator< (const error_category& __rhs) const _NOEXCEPT {return this < &__rhs;}

    friend class __do_message;
};

class _LIBCPP_HIDDEN __do_message
    : public error_category
{
public:
    virtual string message(int ev) const;
};

This is a defect in C++11 tracked by:

http://cplusplus.github.com/LWG/lwg-active.html#2145

which is in Ready status. That means it hasn't been voted in yet, but looks likely to be voted in at the next meeting Spring 2013.

Tip-of-trunk libc++ has aggressively tracked this issue and implemented it even though it hasn't been officially accepted yet. However because llvm servers are currently less than functional, I'm unable to pinpoint the precise revision this was checked in.

The fix involves simply making the existing error_category default constructor public.

Howard

We have a reasonably large body of code using std::error_category subclasses on Visual C++. With libc++, error_category::error_category() is private, preventing this code from porting. Was there a late decision by the standards committee to redact system_error extensibility...?

— Gordon

class _LIBCPP_VISIBLE error_category
{
public:
  virtual ~error_category() _NOEXCEPT;

private:
  error_category() _NOEXCEPT;
  error_category(const error_category&);// = delete;
  error_category& operator=(const error_category&);// = delete;

public:
  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;

  _LIBCPP_ALWAYS_INLINE
  bool operator==(const error_category& __rhs) const _NOEXCEPT {return this == &__rhs;}

  _LIBCPP_ALWAYS_INLINE
  bool operator!=(const error_category& __rhs) const _NOEXCEPT {return !(*this == __rhs);}

  _LIBCPP_ALWAYS_INLINE
  bool operator< (const error_category& __rhs) const _NOEXCEPT {return this < &__rhs;}

  friend class __do_message;
};

class _LIBCPP_HIDDEN __do_message
  : public error_category
{
public:
  virtual string message(int ev) const;
};

This is a defect in C++11 tracked by:

http://cplusplus.github.com/LWG/lwg-active.html#2145

which is in Ready status. That means it hasn't been voted in yet, but looks likely to be voted in at the next meeting Spring 2013.

Tip-of-trunk libc++ has aggressively tracked this issue and implemented it even though it hasn't been officially accepted yet. However because llvm servers are currently less than functional, I'm unable to pinpoint the precise revision this was checked in.

The fix involves simply making the existing error_category default constructor public.

llvm is back up:

r153194 | hhinnant | 2012-03-21 12:18:57 -0400 (Wed, 21 Mar 2012) | 1 line

It appears that the standard accidentally removed the default constructor for error_category. I'm putting it back in. This fixes http://llvm.org/bugs/show_bug.cgi?id=12321.

Howard

I found these references. This is a bug in the standard, which libc++ faithfully
reproduced.

  http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024528.html
  http://cplusplus.github.com/LWG/lwg-active.html#2145

I'm trying the below device as a workaround, though it's quite troublesome to
guarantee that <system_error> is not included before my wrapper, similar to
the __STDC_LIMIT_MACROS mistake.

-- Gordon

#ifndef CARBONITE_COMPAT_SYSTEM_ERROR_INCLUDED
#define CARBONITE_COMPAT_SYSTEM_ERROR_INCLUDED

#if defined(_LIBCPP_SYSTEM_ERROR) || \
    defined(_msvc_include_guard_tbd) || \
    defined(libstdcxx_include_guard_tbd)
# error Include "carbonite/compat/system_error" before <system_error>.
#endif

#include "carbonite/compat/Compiler.h"
#if CARB_TOOLCHAIN_CPP11 || CARB_TOOLCHAIN_VC2010
// This is a gross workaround, so limit its scope. _LIBCPP_VERSION 1001 shipped
// with Xcode 4.5.2, which requires the hack.
# if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 1001
// std::error_category's constructor is inaccessible per the letter of a bug
// in the standard. http://cplusplus.github.com/LWG/lwg-active.html#2145
# define private protected
# endif
# include <system_error>
# undef private
#endif /* CARB_TOOLCHAIN_CPP11 || CARB_TOOLCHAIN_VC2010 */

...

#endif /* !defined(CARBONITE_COMPAT_SYSTEM_ERROR_INCLUDED) */