Відповіді:
Ви можете зробити вперед 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 оголосив typedef", вам потрібно fwd оголосити клас або структуру, і тоді ви можете набрати dedef тип оголошень. Компілятор прийнятний декілька однакових типів.
довга форма:
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
є порожнім за визначенням?
Оскільки для оголошення типу потрібно знати його розмір. Ви можете переслати оголошення вказівника на тип або набрати вказівник на тип.
Якщо ви дійсно хочете, ви можете використовувати ідіому pimpl, щоб утримати включення. Але якщо ви хочете використовувати тип, а не покажчик, компілятор повинен знати його розмір.
Редагувати: j_random_hacker додає важливу кваліфікацію до цієї відповіді, в основному, що розмір повинен знати, щоб використовувати тип, але переадресація може бути зроблена, якщо нам потрібно лише знати, чи існує тип , щоб створити покажчики або посилання на тип. Оскільки ОП не показав код, але поскаржився, що він не складеться, я припустив (напевно правильно), що ОП намагається використовувати тип, а не просто посилатися на нього.
Використання переадресації замість повного #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
У мене була одна і та ж проблема, не хотілося возитися з декількома typedefs в різних файлах, тому я вирішив це з успадкуванням:
було:
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;
Як зауважив Білл Коціас, єдиний розумний спосіб зберегти приватні дані вашої точки конфіденційності та передати їх заяві - це спадкування. Ви можете зробити це трохи приємніше за допомогою 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
>>
{
};