Ответы:
Вы можете сделать вперед typedef. Но делать
typedef A B;
Вы должны сначала отправить декларацию A
:
class A;
typedef A B;
typedef
имена сложных многоуровневых типов шаблонов с использованием прямого объявления таким образом, являются довольно сложными и трудными. Не говоря уже о том, что это может потребовать углубления в детали реализации, скрытые в аргументах шаблона по умолчанию. И конечное решение - это длинный и нечитаемый код (особенно когда типы поступают из различных пространств имен), очень подверженный изменениям в исходном типе.
Для тех из вас, кто, как я, желающих объявить структуру в стиле C, которая была определена с помощью typedef, в некотором коде c ++ я нашел решение, которое выглядит следующим образом ...
// a.h
typedef struct _bah {
int a;
int b;
} bah;
// b.h
struct _bah;
typedef _bah bah;
class foo {
foo(bah * b);
foo(bah b);
bah * mBah;
};
// b.cpp
#include "b.h"
#include "a.h"
foo::foo(bah * b) {
mBah = b;
}
foo::foo(bah b) {
mBah = &b;
}
Чтобы "fwd объявить определение типа", вам нужно объявить класс или структуру, а затем вы можете ввести определение типа. Множественные идентичные определения типов допустимы компилятором.
длинная форма:
class MyClass;
typedef MyClass myclass_t;
короткая форма:
typedef class MyClass myclass_t;
В C ++ (но не в простом C) совершенно законно вводить тип дважды, если оба определения полностью идентичны:
// foo.h
struct A{};
typedef A *PA;
// bar.h
struct A; // forward declare A
typedef A *PA;
void func(PA x);
// baz.cc
#include "bar.h"
#include "foo.h"
// We've now included the definition for PA twice, but it's ok since they're the same
...
A x;
func(&x);
A
поля таким образом, поскольку A
он пуст по определению?
Потому что, чтобы объявить тип, его размер должен быть известен. Вы можете перенаправить объявление указателя на тип или typedef указателя на тип.
Если вы действительно хотите, вы можете использовать идиому pimpl, чтобы уменьшить количество включений. Но если вы хотите использовать тип, а не указатель, компилятор должен знать его размер.
Редактировать: j_random_hacker добавляет важную квалификацию к этому ответу, в основном, что размер должен быть известен, чтобы использовать тип, но предварительное объявление может быть сделано, если нам нужно только знать, что тип существует , чтобы создать указатели или ссылки на тип. Поскольку OP не показывал код, но жаловался, что он не будет компилироваться, я предположил (вероятно, правильно), что OP пытался использовать тип, а не просто ссылаться на него.
Использование предварительных объявлений вместо полных #include
s возможно только в том случае, если вы не собираетесь использовать сам тип (в области действия этого файла), а указатель или ссылку на него.
Чтобы использовать сам тип, компилятор должен знать его размер - следовательно, должно быть видно его полное объявление - следовательно, необходим полный #include
.
Однако размер указателя или ссылки известен компилятору независимо от размера указателя, поэтому достаточно предварительного объявления - оно объявляет имя идентификатора типа.
Интересно, что при использовании указателя или ссылки на class
или struct
типов, компилятор может обрабатывать неполные типы, избавляя вас от необходимости также объявлять типы pointee:
// header.h
// Look Ma! No forward declarations!
typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere
typedef class A& ARef;
typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere
typedef struct B& BRef;
// Using the name without the class/struct specifier requires fwd. decl. the type itself.
class C; // fwd. decl. type
typedef C* CPtr; // no class/struct specifier
typedef C& CRef; // no class/struct specifier
struct D; // fwd. decl. type
typedef D* DPtr; // no class/struct specifier
typedef D& DRef; // no class/struct specifier
У меня была та же проблема, я не хотел связываться с несколькими определениями типов в разных файлах, поэтому я решил ее с помощью наследования:
был:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
сделал:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Работал как шарм. Конечно, мне пришлось изменить любые ссылки с
BurstBoss::ParticleSystem
просто
ParticleSystem
Я заменил typedef
( using
если быть точным) наследованием и наследованием конструктора (?).
оригинал
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
Заменены
struct CallStack // Not a typedef to allow forward declaration.
: public std::array<StackFrame, MAX_CALLSTACK_DEPTH>
{
typedef std::array<StackFrame, MAX_CALLSTACK_DEPTH> Base;
using Base::Base;
};
Таким образом, я смог переслать объявить CallStack
с:
class CallStack;
Как отметил Билл Коциас, единственный разумный способ сохранить подробности typedef вашей точки и объявить их вперед - это наследование. Вы можете сделать это немного лучше с C ++ 11, хотя. Учти это:
// LibraryPublicHeader.h
class Implementation;
class Library
{
...
private:
Implementation* impl;
};
// LibraryPrivateImplementation.cpp
// This annoyingly does not work:
//
// typedef std::shared_ptr<Foo> Implementation;
// However this does, and is almost as good.
class Implementation : public std::shared_ptr<Foo>
{
public:
// C++11 allows us to easily copy all the constructors.
using shared_ptr::shared_ptr;
};
Как и @BillKotsias, я использовал наследование, и оно работало на меня.
Я изменил этот беспорядок (который требовал все заголовки повышения в моем объявлении * .h)
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>
typedef boost::accumulators::accumulator_set<float,
boost::accumulators::features<
boost::accumulators::tag::median,
boost::accumulators::tag::mean,
boost::accumulators::tag::min,
boost::accumulators::tag::max
>> VanillaAccumulator_t ;
std::unique_ptr<VanillaAccumulator_t> acc;
в эту декларацию (* .h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
и реализация (* .cpp) была
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>
class VanillaAccumulator : public
boost::accumulators::accumulator_set<float,
boost::accumulators::features<
boost::accumulators::tag::median,
boost::accumulators::tag::mean,
boost::accumulators::tag::min,
boost::accumulators::tag::max
>>
{
};