Используй директивы условной компиляции типа #ifdef или сразу #progma once
Я их итак использую, здесь писать их, для краткости, не стал.
Использую их одновременно: #pragma once, для тех компиляторов, которые его понимают,
#ifdef для тех, которые #pragma once не понимают.
Обычно пишу так (доп. предварительные декларации только для перекрёстно зависимых классов):
В первом модуле A.hpp
C++:
#pragma once
#ifndef A_HPP
#define A_HPP
#include "B.hpp"
class Cls_B;
class Cls_A {
// Функции:
public:
std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const;
};
#endif A_HPP
Во втором модуле B.hpp
C++:
#pragma once
#ifndef B_HPP
#define B_HPP
#include "A.hpp"
class Cls_A;
class Cls_B {
// Типы:
public:
typedef std::vector< std::vector< double >::const_iterator > TFEPos;
// Функции:
public:
void funcB( const Cls_A& );
};
#endif B_HPP
struct SomeStruct {
int a, b;
};
struct Somestruct; // для тех, что с первого раза не понял, видимо.
И это Я прекрасно понимаю!
Однако, при компиляции A.cpp, без предварительные декларации class Cls_B;
компилятор ругается так:
1>B.hpp(143): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>B.hpp(143): error C2143: синтаксическая ошибка: отсутствие "," перед "&"
B.hpp(143) указывает на строчку
void funcB( const Cls_A& );
при компиляции B.cpp ошибки полностью аналогичные, компилятор ругается на
std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const;
После добавления во второй модуль предварительной декларации
class Cls_A;
первый модуль успешно компилируется.
А также, после добавления в первый модуль предварительной декларации
class Cls_B;
второй модуль успешно компилируется, если без Cls_B::TFEPos.
Далее всё нормально работает.
Как сделать с Cls_B::TFEPos незнаю, в этом и вопрос.
Проблема именно в перекрёстной зависимости.
Далее просто попытка объяснить успешность предварительной декларации.
Что происходит при компиляции A.cpp, как это Я понимаю:
C++:
#pragma once
#ifndef A_HPP
#define A_HPP - определяется A_HPP
#include "B.hpp" - включается содержимое "B.hpp", развернём его в следующем коде
class Cls_B;
class Cls_A {
// Функции:
public:
std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const;
};
#endif A_HPP
Разворачиваем "B.hpp"
C++:
#pragma once
#ifndef A_HPP
#define A_HPP - определяется A_HPP
#pragma once
#ifndef B_HPP
#define B_HPP - определяется B_HPP
#include "A.hpp" - предполагается включение содержимого "A.hpp", но, поскольку, A_HPP уже определено, то повторно он не включается!
class Cls_A; - для этого доп. декларация, сам класс Cls_A, как Мы видим, описан ниже
class Cls_B {
// Типы:
public:
typedef std::vector< std::vector< double >::const_iterator > TFEPos;
// Функции:
public:
void funcB( const Cls_A& ); - компилятор понимает этот код благодаря доп. декларации, без неё эта строчка ему непонятна!
};
#endif B_HPP
class Cls_B; - эта строчка, при компиляции A.cpp, игнорируется, поскольку класс Cls_B уже объявлен
class Cls_A {
// Функции:
public:
std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const; - класс Cls_B уже объявлен и эта строчка компилятору понятна
};
#endif A_HPP
модуль успешно компилируется!
Что происходит при компиляции B.cpp, как это Я понимаю:
C++:
#pragma once
#ifndef B_HPP
#define B_HPP - определяется B_HPP
#include "A.hpp" - включается содержимое "A.hpp", развернём его в следующем коде
class Cls_A;
class Cls_B {
// Типы:
public:
typedef std::vector< std::vector< double >::const_iterator > TFEPos;
// Функции:
public:
void funcB( const Cls_A& );
};
#endif B_HPP
Разворачиваем "A.hpp"
C++:
#pragma once
#ifndef B_HPP
#define B_HPP - определяется B_HPP
#pragma once
#ifndef A_HPP
#define A_HPP - определяется A_HPP
#include "B.hpp" - предполагается включение содержимого "B.hpp", но, поскольку, B_HPP уже определено, то повторно он не включается!
class Cls_B; - для этого доп. декларация, сам класс Cls_B, как Мы видим, описан ниже
class Cls_A {
// Функции:
public:
std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const; - компилятор понимает первый аргумент благодаря доп. декларации, но не второй
};
#endif A_HPP
class Cls_A; - эта строчка, при компиляции B.cpp, игнорируется, поскольку класс Cls_A уже объявлен
class Cls_B {
// Типы:
public:
typedef std::vector< std::vector< double >::const_iterator > TFEPos;
// Функции:
public:
void funcB( const Cls_A& ); - класс Cls_A уже объявлен и эта строчка компилятору понятна
};
#endif B_HPP
Если в классе объявлена функция не std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const;
а std::vector<double> funcA( const Cls_B& ) const;
то модуль успешно компилируется!
но нужно именно std::vector<double> funcA( const Cls_B& , const Cls_B::TFEPos& ) const;
Если Мои рассуждения неправильны, то поправьте.
Как решить эту проблему с вложенным типом или с перекрёстной зависимостью?