недопустимое использование неполного типа при обработке исключений

Как реализовать следующее без проблем, связанных с «недопустимым использованием неполного типа»?

class A { // line#10
/*(...) some fields and methods here. */
// more fields of the following functionality exist, storing data about object A's state.
int SomeField;
class Exception {
/*(...) some fields and methods here. */
public: enum ProblemCase { /*(...) */ };
protected: Exception( ProblemCase issue, int additionalData ) { /*(...)*/ } // line#29
friend Exception A::BuildException( ProblemCase ); // line#34
};
inline Exception BuildException( Exception::ProblemCase issue ) {
return Exception( issue, SomeField ); // line#99
}
};

обновление: журнал ошибок:

A.hpp:34:72: error: invalid use of incomplete type ‘class A’
A.hpp:10:7: error: forward declaration of ‘class A’
A.hpp: In member function ‘A::Exception A::BuildException(A::Exception::ProblemCase)’:
A.hpp:29:20: error: ‘A::Exception::Exception(A::Exception::ProblemCase, int)’ is protected
A.hpp:99:46: error: within this context

обратите внимание, что имена изменены, поэтому количество символов в журнале ошибок неверно.

0

Решение

Это невозможно с простой перестановкой деклараций. Немного основной требуется реструктуризация.

class A {

public:
class Exception;

private:
class AHelper
{
public:
friend class A;
class ExceptionBase
{
public:
typedef enum {Something} ProblemCase;
};
private:
inline static Exception BuildException(ExceptionBase::ProblemCase issue, int something);
};

int SomeField;

public:
class Exception : public AHelper::ExceptionBase
{
public:
using AHelper::ExceptionBase::ProblemCase;
protected:
Exception(ProblemCase issue, int additionalData) {}
friend Exception AHelper::BuildException(ProblemCase, int);
};

inline Exception BuildException(Exception::ProblemCase issue);
};

inline A::Exception A::AHelper::BuildException(A::Exception::ProblemCase issue, int something)
{
return A::Exception(issue, something);
}

inline A::Exception A::BuildException(A::Exception::ProblemCase issue)
{
return AHelper::BuildException(issue, SomeField);
}
0

Другие решения

Конструктор для Exception защищен, что означает, что только классы, полученные из Exception разрешено использовать это. Класс A не является производным от ExceptionВот почему вы получаете сообщение об ошибке в строке 99.

Изменить: Хорошо, поэтому я взял приведенный выше код, очистил его, чтобы он был скомпилирован, и я получаю точно такие же сообщения об ошибках — хорошо для воспроизведения!

Решение, которое я мог бы найти, состоит в том, чтобы удалить «защищенный» из конструктора и сделать общедоступным. Я не могу найти другое решение, которое действительно работает, и я не уверен, ПОЧЕМУ оно не работает так, как написано.

class A {
int SomeField;
class Exception
{
public:
enum ProblemCase { PB1, PB2 };
public:
Exception( ProblemCase issue, int additionalData ) {  }
};
inline Exception BuildException( Exception::ProblemCase issue ) {
return Exception( issue, SomeField ); // line#99
}
};
0

Просто как «академический» пример, самый близкий, который я мог получить. Примечание: НЕ рекомендуется.

#include <type_traits>

struct A { // line#10
/*(...) some fields and methods here. */
// more fields of the following functionality exist, storing data about object A's state.
int SomeField;

class Exception;

template < typename T >
inline Exception BuildException( T issue );

class Exception {
/*(...) some fields and methods here. */
public: enum ProblemCase { FIRST /*(...) */ };
protected: Exception( ProblemCase issue, int additionalData ) { /*(...)*/ } // line#29
// accepted by clang, not by g++??
// friend Exception A::BuildException<ProblemCase>( ProblemCase ); // line#34

// accepted by both
template < typename T >
friend Exception A::BuildException( T ); // line#34
};
};

// there's no need to define it outside the class
// (I originally used an explicit specialization)
template < typename T >
A::Exception A::BuildException( T issue ) {
// optional
static_assert(std::is_same<typename std::remove_const<T>::type, Exception::ProblemCase>::value, "Wrong type!");

return Exception( issue, SomeField ); // line#99
}

int main()
{
A a;
a.BuildException(A::Exception::FIRST);
}
0