DevCybran DevCybran - 2 months ago 8
C++ Question

'make_error_code' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation

I am using

boost::system::error_code
(of boost 1.62.0) to define custom error codes in C++ like in the following minified example:

#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>

namespace mynamespace {

enum class MyErrorCodeEnum : int {
ERROR1 = 1,
ERROR2 = 2,
};


class MyErrorCategory: public boost::system::error_category
{
public:
static const MyErrorCategory& instance() {
static MyErrorCategory category;
return category;
}

// error_category interface
public:
virtual const char* name() const noexcept {
return "MyErrorCategory";
}
virtual std::string message(int ev) const {
return "dummy";
}
};

}

namespace boost {
namespace system {

inline error_code make_error_code(const mynamespace::MyErrorCodeEnum e) {
return error_code(static_cast<int>(e), mynamespace::MyErrorCategory::instance());
}

inline error_condition make_error_condition(const mynamespace::MyErrorCodeEnum e) {
return error_condition(static_cast<int>(e), mynamespace::MyErrorCategory::instance());
}

template<>
struct is_error_code_enum<mynamespace::MyErrorCodeEnum>: public std::true_type {};

}
}


int main(int argc, char *argv[])
{
throw boost::system::error_code(mynamespace::MyErrorCodeEnum::ERROR1);
}


This was working just fine using MSVC. However, trying to move to mingw 5.3.0, the following error is reported by the compiler:

boost/system/error_code.hpp: In instantiation of 'boost::system::error_code::error_code(ErrorCodeEnum, typename boost::enable_if<boost::system::is_error_code_enum<ErrorCodeEnum> >::type*) [with ErrorCodeEnum = mynamespace::MyErrorCodeEnum; typename boost::enable_if<boost::system::is_error_code_enum<ErrorCodeEnum> >::type = void]':
main.cpp:52:70: required from here
boost/system/error_code.hpp:329:32: error: 'make_error_code' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
*this = make_error_code(e);
^
main.cpp:35:19: note: 'boost::system::error_code boost::system::make_error_code(mynamespace::MyErrorCodeEnum)' declared here, later in the translation unit
inline error_code make_error_code(const mynamespace::MyErrorCodeEnum e) {
^


I can see why it is being reported (the
make_error_code
function is declared after it is being referenced by the constructor of the
error_code
template class), but how am I supposed to solve this problem?

Answer

Thankfully coliru error messages were more explanatory, here is a working version:

#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>

namespace mynamespace {

enum class MyErrorCodeEnum : int {
    ERROR1 = 1,
    ERROR2 = 2,
};


class MyErrorCategory: public boost::system::error_category
{
public:
    static const MyErrorCategory& instance() {
        static MyErrorCategory category;
        return category;
    }

    // error_category interface
public:
    virtual const char* name() const noexcept {
        return "MyErrorCategory";
    }
    virtual std::string message(int ev) const {
        return "dummy";
    }
};


inline boost::system::error_code make_error_code(const MyErrorCodeEnum e) {
    return boost::system::error_code(static_cast<int>(e), MyErrorCategory::instance());
}

inline boost::system::error_condition make_error_condition(const MyErrorCodeEnum e) {
    return boost::system::error_condition(static_cast<int>(e), MyErrorCategory::instance());
}

}

template<>
struct boost::system::is_error_code_enum<mynamespace::MyErrorCodeEnum>: public std::true_type {};


int main(int argc, char *argv[])
{
    throw boost::system::error_code(mynamespace::MyErrorCodeEnum::ERROR1);
}

The messages generated by clang on coliru where more extensive:

In file included from main.cpp:1:
/usr/local/include/boost/system/error_code.hpp:329:17: error: call to function 'make_error_code' that is neither visible in the template definition nor found by argument-dependent lookup
        *this = make_error_code(e);
                ^
main.cpp:52:11: note: in instantiation of function template specialization 'boost::system::error_code::error_code<mynamespace::MyErrorCodeEnum>' requested here
    throw boost::system::error_code(mynamespace::MyErrorCodeEnum::ERROR1);
          ^
main.cpp:35:19: note: 'make_error_code' should be declared prior to the call site or in namespace 'mynamespace'
inline error_code make_error_code(const mynamespace::MyErrorCodeEnum e) {
                  ^
1 error generated.

So yeah, the argument dependent lookup failed, since the namespace did not provide an implementation for make_error_code so you either had to move them before the template instantiation or in the same namespace. Here is a similar question where the answers explain this in more detail.

This works for gcc as well (in the case is_error_code_enum is specialized inside boost::system):

#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>

namespace mynamespace {

enum class MyErrorCodeEnum : int {
    ERROR1 = 1,
    ERROR2 = 2,
};

}

namespace boost {
namespace system {

template<>
struct is_error_code_enum<mynamespace::MyErrorCodeEnum>: public std::true_type {};

}
}

namespace mynamespace {

class MyErrorCategory: public boost::system::error_category
{
public:
    static const MyErrorCategory& instance() {
        static MyErrorCategory category;
        return category;
    }

    // error_category interface
public:
    virtual const char* name() const noexcept {
        return "MyErrorCategory";
    }
    virtual std::string message(int ev) const {
        return "dummy";
    }
};


inline boost::system::error_code make_error_code(const MyErrorCodeEnum e) {
    return boost::system::error_code(static_cast<int>(e), MyErrorCategory::instance());
}

inline boost::system::error_condition make_error_condition(const MyErrorCodeEnum e) {
    return boost::system::error_condition(static_cast<int>(e), MyErrorCategory::instance());
}

}

int main(int argc, char *argv[])
{
    throw boost::system::error_code(mynamespace::MyErrorCodeEnum::ERROR1);
}