Форвардное объявление typedef в С++

Почему компилятор не позволяет мне отправить объявление typedef?

Предполагая, что это невозможно, какая наилучшая практика для сохранения маленького дерева включения?

Ответ 1

Вы можете выполнить форматирование typedef. Но делать

typedef A B;

вы должны сначала направить объявление A:

class A;

typedef A B;

Ответ 2

Для тех, кто из вас, как я, ищущих вперед, объявляет структуру C-стиля, которая была определена с помощью typedef, в некотором С++-коде, я нашел решение, которое выглядит следующим образом...

// 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;
 }

Ответ 3

В С++ (но не просто 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 ok since they're the same
...
A x;
func(&x);

Ответ 4

Чтобы "fwd объявить typedef", вам нужно объявить класс или структуру, а затем вы можете объявить тип typedef. Несколько идентичных typedefs приемлемы компилятором.

длинная форма:

class MyClass;
typedef MyClass myclass_t;

короткая форма:

typedef class MyClass myclass_t;

Ответ 5

Чтобы объявить тип, его размер должен быть известен. Вы можете переслать объявление указателя на тип или typedef указатель на тип.

Если вы действительно этого хотите, вы можете использовать идиому pimpl, чтобы поддерживать включенность. Но если вы хотите использовать тип, а не указатель, компилятор должен знать его размер.

Изменить: j_random_hacker добавляет важную квалификацию к этому ответу, в основном, что размер должен знать, чтобы использовать этот тип, но может быть сделано объявление вперед, если нам нужно только знать тип существует, чтобы создать указатели или ссылки на тип. Поскольку ОП не показывал код, но жаловался, что он не будет компилироваться, я предположил (возможно, правильно), что ОП пытался использовать этот тип, а не просто ссылался на него.

Ответ 6

Использование форвардных деклараций вместо полного #include возможно только тогда, когда вы не намереваетесь использовать сам тип (в области этого файла), но указатель или ссылку на него.

Чтобы использовать сам тип, компилятор должен знать его размер - следовательно, его полная декларация должна быть видна, поэтому необходим полный #include.

Однако размер указателя или ссылки известен компилятору независимо от размера указателя, поэтому достаточно объявления прямого объявления - оно объявляет имя идентификатора типа.

Интересно, что при использовании указателей или ссылок на типы class или struct компилятор может обрабатывать неполные типы, сохраняя при этом необходимость переадресации также объявлять типы адресатов:

// 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 

Ответ 7

У меня была такая же проблема, я не хотел связываться с несколькими typedef в разных файлах, поэтому я решил ее с наследованием:

было:

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

Ответ 8

Как отметил Билл Коциас, единственный разумный способ сохранить данные typedef вашей точки в частном порядке, а forward объявить их с наследованием. Вы можете сделать это немного лучше с С++ 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;
};

Ответ 9

Как и @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
>>
{
};

Ответ 10

Я заменил 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;