c++ - 实现 std::error_category,与自定义命名空间一起使用时的名称解析问题

标签 c++ namespaces

总之 ,问题是名称解析。

说明:
我正在枚举错误代码并使用它们来派生/实现 std::error_condition类,但是将实现包装到 2 个单独的命名空间时会出现问题,一个用于枚举,另一个用于代码实现。

解释起来并不容易,所以我制作了一个最小的可编译代码,您可以将其复制/粘贴到编辑器中并尝试编译。

我在代码顶部放置了一个(注意:)注释,这是我为编译代码所做的工作,但我需要单独的命名空间,如下面的代码所示,但名称解析不起作用,我不知道如何修复它。

#include <string>
#include <system_error>


// *NOTE*: if we rename this from 'enums' to 'app' (comment below) and do
// the needed name change changes in the code it will compile just fine
//namespace app
namespace enums
{
    // error type enum
    enum class Error
    {
        SignalFail,         // failed to set up or execute signal
        BadArgument,        // bad argument passed to function
        InvalidPointer,     // Pointer is invalid
        NoImplementation,   // No implementation
        OutOfRange,         // Out of range
        AlocationFailed,    // Failed to alocate memory
        MemoryReadFailed,   // Failed to read memory
        Unexpected          // Unexpected execution flow
    };

    // error condition enum
    enum class Condition
    {
        code_error,
        unknown_error
    };
}

// Register Error and Condition as error enum and condition enum
namespace std
{
    template<>
    struct is_error_code_enum<enums::Error> :
        public true_type {};

    template<>
    struct is_error_condition_enum<enums::Condition> :
        public true_type {};
}

namespace app
{
    // Category types are used to identify the source of an error.
    // They also define the relation between error_code and error_condition objects of its category,
    // as well as the message set for error_code objects.
    class error_category_t :
        public std::error_category
    {
    public:
        error_category_t() noexcept {};
        inline const char* name() const noexcept override;
        std::error_condition default_error_condition(int err_value) const noexcept override;
        inline bool equivalent(const std::error_code& err_code, int err_value) const noexcept override;
        inline bool equivalent(int err_value, const std::error_condition& err_cond) const noexcept override;
        std::string message(int ev) const override;
    private:
        error_category_t(const error_category_t&) = delete;
        error_category_t(error_category_t&&) = delete;
        error_category_t& operator=(const error_category_t&) = delete;
        error_category_t& operator=(error_category_t&&) = delete;
    } const error_category;

    const char* error_category_t::name() const noexcept
    {
        return "app category";
    }

    bool error_category_t::equivalent(const std::error_code& err_code, int err_value) const noexcept
    {
        return *this == err_code.category() &&
            static_cast<int>(default_error_condition(err_code.value()).value()) == err_value;
    }

    bool error_category_t::equivalent(int err_value, const std::error_condition& err_cond) const noexcept
    {
        return default_error_condition(err_value) == err_cond;
    }

    //
    // make_error_condition overload to generate custom conditions:
    // This function is called by error_condition's constructor for error condition enum types,
    // and should be overloaded for all custom error condition enum types in order to
    // provide a mechanism to generate the appropriate error_condition objects from them.
    //
    inline std::error_condition make_error_condition(enums::Condition ec) noexcept
    {
        return std::error_condition(static_cast<int>(ec), error_category);
    }

    //
    // This function is called by error_code's constructor for error code enum types
    //
    inline std::error_code make_error_code(enums::Error code) noexcept
    {
        return std::error_code(static_cast<int>(code), error_category);
    }
}

namespace app
{
    std::error_condition error_category_t::default_error_condition(int err_value) const noexcept
    {
        switch (static_cast<enums::Error>(err_value))
        {
        case enums::Error::SignalFail:
        case enums::Error::BadArgument:
        case enums::Error::InvalidPointer:
        case enums::Error::NoImplementation:
        case enums::Error::OutOfRange:
        case enums::Error::AlocationFailed:
        case enums::Error::MemoryReadFailed:
        case enums::Error::Unexpected:
            return std::error_condition(enums::Condition::code_error);
        default:
            return std::error_condition(enums::Condition::unknown_error);
        }
    }

    std::string error_category_t::message(int err_value) const
    {
        switch (static_cast<enums::Error>(err_value))
        {
        case enums::Error::SignalFail:
            return "Signaling failed";
        case enums::Error::BadArgument:
            return "Bad Argument";
        case enums::Error::InvalidPointer:
            return "Invalid pointer";
        case enums::Error::NoImplementation:
            return "No implementation";
        case enums::Error::OutOfRange:
            return "Out of range";
        case enums::Error::AlocationFailed:
            return "Memory allocation failed";
        case enums::Error::MemoryReadFailed:
            return "Memory read failed";
        case enums::Error::Unexpected:
            return "Unexpected execution flow";
        default:
            return "Unknown error";
        }
    }
}

最佳答案

虽然我个人建议您将枚举放在与类别相同的命名空间中,但关键问题是 make_error_conditionmake_error_code函数必须与枚举位于相同的命名空间中。两者std::error_codestd::error_condition构造函数对这两个函数执行 ADL 查找。

inline std::error_condition make_error_condition(enums::Condition ec) noexcept
inline std::error_code make_error_code(enums::Error code) noexcept

关于c++ - 实现 std::error_category,与自定义命名空间一起使用时的名称解析问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56560209/

相关文章:

c++ - boost 找不到文件

reactjs - 错误 TS2694 : Namespace '"react "' has no exported member ' ReactNode', 'DetailedHTMLProps'、 'HTMLAttributes'、 'SyntheticEvent'、 'HTMLProps'

xml - 取消声明 XML 1.1 中的命名空间和 "Prefix Declared"命名空间约束

c++ - 我应该为 size_t 包含 stddef.h 还是 cstddef

c++ - 在 Visual Studio 2010 C++ 中包含命名空间

c++ - 类中的常量?

c++ - 如何在 C++ 中使父类(super class)的虚函数可被孙子覆盖?

Windows 等同于 Linux namespace (每个进程文件系统挂载)?

c++ - 如何在C++中将字符串转换为json格式?

c++ - 是否可以*安全地*从函数返回 TCHAR*?