C ++ 'da bir typedef'in ileri bildirimi


235

Derleyici bir typedef bildirmeme neden izin vermiyor?

İmkansız olduğunu varsayarsak, dahil etme ağacımı küçük tutmanın en iyi yolu nedir?

Yanıtlar:


170

Ileri typedef yapabilirsiniz. Ama yapmak

typedef A B;

ilk önce beyan etmelisiniz A:

class A;

typedef A B;

11
Sonunda +1 çünkü teknik olarak "ileri-typedef" yazamasanız da (yani "typedef A;" yazamazsınız), OP'nin yukarıdaki hilenizi kullanarak başarmak istediklerini neredeyse kesin olarak gerçekleştirebilirsiniz.
j_random_hacker

9
Ancak, typedef değişirse, tüm bu ileri bildirimleri de değiştirebileceğinizi unutmayın; eski ve yeni typedef aynı arabirime sahip türleri kullanarak kaçırırsınız.
matematik

50
Genel olarak bu yararlı bir çözüm değildir. Örneğin, typedefbir ileri bildirimi kullanarak karmaşık çok düzeyli bir şablon türünü bu şekilde adlandırırsanız, oldukça karmaşık ve zordur. Varsayılan şablon argümanlarında gizlenmiş uygulama ayrıntılarına dalmayı gerektirebileceğinden bahsetmiyorum bile. Ve son çözüm, orijinal tipte değişmeye çok eğilimli uzun ve okunamayan bir koddur (özellikle türler çeşitli ad alanlarından geldiğinde).
Adam Badura

3
Ayrıca bu, "beyan ayrıntıları" (tam değil ama yine de ... olsa bile) gösterirken, ileri bildirimin arkasındaki fikir onları gizlemekti.
Adam Badura

3
@windfinder: Şunları yapar: <sınıf T> şablonu A sınıfı; typedef A <C> B;
milianw

47

Benim gibi olanlar için, ileriye bakmak isteyen tip C kullanılarak tanımlanmış bir C tarzı yapı ilan etmek, bazı c ++ kodunda, ben aşağıdaki gibi bir çözüm buldum ...

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

4
@LittleJohn Bu çözümle ilgili sorun, kukla adının _bah genel API'nin bir parçası olarak kabul edilmemesidir. İleri delcare dosyasına bakın.
user877329

23

"Fwd bir typedef bildirmek" için fwd bir sınıf ya da bir yapı bildirmeniz gerekir ve daha sonra bildirilen tip yazabilirsiniz. Birden fazla özdeş tip tanımlayıcısı derleyici tarafından kabul edilebilir.

uzun biçim:

class MyClass;
typedef MyClass myclass_t;

kısa form:

typedef class MyClass myclass_t;

Bunun en çok oylanan sorudan farkı nedir? stackoverflow.com/a/804956/931303
Jorge Leitao

1
@ JorgeLeitão nasıl farklı olduğunu görmüyor musun? Bunu tek bir satırda nasıl yapacağınızı göstermez.
Pavel P

17

C ++ 'da (düz C değil), her iki tanım da tamamen aynı olduğu sürece, bir türü iki kez yazmak tamamen yasaldır :

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

34
Bakım Hayır Hayır. Bu tür şeyler er ya da geç keisterde ısırır.
Mark Storer

3
@MarkStorer, en azından derleyici herhangi bir farkı yakalayacak ve bir hata oluşturacaktır. Visual C ++ ile bunu doğruladım.
Alan

Güzel, ama tanım gereği boş olduğu için Aalanları bu şekilde nasıl tanımlıyorsunuz A?
Patrizio Bertoni

10

Çünkü bir tür beyan etmek için boyutunun bilinmesi gerekir. İşaretçiyi türüne iletebilir veya türe bir işaretçi yazabilirsiniz.

Eğer gerçekten istiyorsanız, pimpl deyimini kullanarak içerilen şeyleri aşağıda tutabilirsiniz. Ancak bir işaretçi yerine bir tür kullanmak istiyorsanız, derleyici boyutunu bilmelidir.

Düzenleme: j_random_hacker boyutu ihtiyaçlarını bilmek gerekir temelde ki bu cevaba önemli bir nitelik katar kullanmak türü, özellikle de bir ileri beyanı yapılabilir sadece tip bilmek gerekiyorsa var , işaretçileri veya referanslar oluşturmak için yazın. OP kod göstermedi, ancak derlemek olmaz şikayet beri, ben OP (sadece doğru) tip sadece kullanmaya değil, tipini kullanmaya çalıştığını varsaydım .


35
Sınıf türlerinin ileri bildirimleri, bu türleri büyüklükleri hakkında bilgi sahibi olmadan beyan eder. Ayrıca, bu tür eksik tiplere yönelik işaretçiler ve referanslar tanımlayabilmenin yanı sıra, parametreleri alan ve / veya bu tipte bir değer döndüren fonksiyonlar da bildirilebilir (ancak tanımlanamaz).
j_random_hacker

3
Üzgünüm, bunun iyi bir varsayım olduğunu düşünmüyorum. Bu cevap konunun yanında. Bu bir ileri tanım beyanı tipedef örneğidir.
Çerez

6

İleri bildirimleri kullanarak yerine tam bir #includes Eğer sadece zaman mümkündür değil (bu dosyanın kapsamı) türü kendisi ama buna bir işaretçi veya referans kullanarak müstakbel.

Türün kendisini kullanmak için, derleyici boyutunu bilmelidir - bu nedenle tam beyanı görülmelidir - bu nedenle bir tam #includegereklidir.

Bununla birlikte, bir işaretçi veya referansın boyutu derleyicinin boyutuna bakılmaksızın derleyici tarafından bilinir, bu nedenle ileri bir bildirim yeterlidir - bir tür tanımlayıcı adı bildirir.

İlginç bir şekilde, işaretçi veya referans classveya structtürler kullanılırken, derleyici eksik türleri işleyebilir ve ayrıca pointee türlerini de bildirmeniz gerekir:

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

2

Aynı sorunu vardı, farklı dosyalarda birden fazla typedefs ile uğraşmak istemiyordu, bu yüzden miras ile çözdüm:

oldu:

class BurstBoss {

public:

    typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...

yaptı:

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{

public:

    ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
    };
};

Bir cazibe gibi çalıştı. Tabii ki, herhangi bir referansı değiştirmek zorunda kaldım.

BurstBoss::ParticleSystem

basitçe

ParticleSystem

1

Ben değiştirilir typedef( usingmiras ve yapıcı miras birlikte olmak özgü) (?).

orijinal

using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;

Değiştirilen

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

Bu şekilde beyanı şu şekilde iletebildim CallStack:

class CallStack;

0

Bill Kotsias'ın belirttiği gibi, noktanızın typedef ayrıntılarını gizli tutmanın ve ileriye beyan etmenin tek makul yolu kalıtımdır. Gerçi C ++ 11 ile biraz daha güzel yapabilirsiniz. Bunu düşün:

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

0

@BillKotsias gibi, kalıtım kullandım ve benim için çalıştı.

Bu karışıklığı değiştirdim.

#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;

bu bildirime (* .h)

class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;

ve uygulama (* .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
>>
{
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.