Ошибка «инициализатор не называет нестатический элемент данных или базовый класс», когда инициализатор является именем базового класса

Я сталкиваюсь со следующей проблемой. В файле my_exception.h я определил свой собственный класс исключений, унаследованный от std::exception :

// File "my_exception.h"
#include <exception>
#include <string>

namespace proj { namespace exception {

struct Exception : public std::exception {
    explicit Exception(const std::string& msg) noexcept : msg_(msg) { }

    inline const char* what() const noexcept override { return msg_.c_str(); }

private:
    std::string msg_;
};

} }

Затем я определил производный класс исключений с именем BadParameterAccess в другом пространстве имен, разделив объявление и реализацию в файлах .h и .cpp соответственно:

// File parameter_exception.h
#include "exception.h"

namespace proj { namespace parameter {

struct BadParameterAccess final : public exception::Exception
{
    BadParameterAccess() noexcept;
};

} }

// File parameter_exception.cpp
#include "parameter_exception.h"

namespace proj { namespace parameter {

BadParameterAccess::BadParameterAccess() noexcept
    : exception::Exception("[BadParameterAccess] parameter not set yet."){ }

} }

Я попытался скомпилировать этот код, используя несколько компиляторов. С clang 6.0 я получаю следующую ошибку:

parameter_exception.cpp:7:18: error: initializer 'Exception' does not name a non-static data member or base class; did you mean the base class 'Exception'?
    : exception::Exception("[BadParameterAccess] parameter not set yet."){ }
                 ^~~~~~~~~
                 Exception
./parameter_exception.h:11:35: note: base class 'exception::Exception' specified here
struct BadParameterAccess final : public exception::Exception
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~

g ++ 7 выдает эквивалентную ошибку, а Visual Studio 2017 дает следующее:

parameter_exception.cpp(8): error C2039: 'Exception': is not a member of 'std::exception'

Код прекрасно компилируется, когда либо:

  1. в файле parameter_exception.cpp я указываю полный путь для инициализатора базового класса ( proj::exception::Exception ), или
  2. в файле parameter_exception.cpp я удаляю пространства имен из инициализатора базового класса ( Exception ), или
  3. в файле my_exception.h я удаляю наследование из std::exception , или
  4. Я переименую свое exception в пространстве имен другим способом.

Насколько я понял из разных ошибок, которые я получил, компилятор ожидает найти член с именем Exception внутри класса std::exception а не внутри exception пространства имен, но я не понимаю, почему это происходит. Более того, я ожидал, что компилятор выдаст мне ошибку, когда я вначале унаследую от exception::Exception в заголовочном файле parameter_exception.h , но это не так.

Может кто-нибудь объяснить мне причину?

Заранее спасибо.

Всего 2 ответа


как говорит @molbdnilo, существует проблема поиска имени. проблема в том, что имя «исключение» используется для исключения пространства имен и стандартная структура :: исключение. Я удалил код и комментарии из кода, который вы опубликовали.

namespace standard {
    struct exception{
        explicit exception() noexcept { }
    };
}
namespace exception {
    struct A: public standard::exception {
        explicit A() noexcept { }
    };
}
namespace parameter {
    struct BadParameterAccess final : public exception::A
    {
        //BadParameterAccess() noexcept : exception::A() { }; // KO
        BadParameterAccess() noexcept : ::exception::A() { }; // OK
    };
}

namespace standard1 {
    struct exception1{
        explicit exception1() noexcept { }
    };
}
namespace exception2 {
    struct A: public standard1::exception1 {
        explicit A() noexcept { }
    };
}
namespace parameter1 {
    struct BadParameterAccess1 final : public exception2::A
    {
        BadParameterAccess1() noexcept : exception2::A() { }; // OK
        //BadParameterAccess1() noexcept : ::exception2::A() { }; // OK
    };
}

Несколько вещей, которые вы можете попробовать:

1-й: попробуйте использовать virtual при наследовании:

struct Exception : virtual public std::exception;

2-й: Попробуйте использовать protected модификатор для msg_.

std::runtime_error : если вам все равно, вы можете унаследовать std::runtime_error из библиотеки stdexcept .

4-е: у вас также может быть проблема круговой зависимости.


Есть идеи?

10000