web-dev-qa-db-ja.com

C ++でのtypedefの前方宣言

コンパイラーがtypedefの前方宣言を許可しないのはなぜですか?

不可能だと仮定して、包含ツリーを小さく保つためのベストプラクティスは何ですか?

216
user96825

前方typedefを行うことができます。しかし、すること

typedef A B;

最初にAを前方宣言する必要があります。

class A;

typedef A B;
156
Hong Jiang

Typedefを使用して定義されたCスタイルの構造体を前方宣言しようとしている私のような皆さんのために、いくつかの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;
 }
43
LittleJohn

C++(プレーンCではありません)では、両方の定義が完全同一である限り、型を2回typedefすることは完全に合法です:

// 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);
17
Adam Rosenfield

「fwdでtypedefを宣言」するには、クラスまたは構造体をfwd宣言する必要があります。その後、宣言した型をtypedefできます。複数の同一のtypedefがコンパイラーで受け入れられます。

長い形式:

class MyClass;
typedef MyClass myclass_t;

ショートフォーム:

typedef class MyClass myclass_t;
16
Pavel

型を宣言するには、そのサイズを知る必要があります。型へのポインターを前方宣言するか、型へのポインターをtypedefすることができます。

本当にしたい場合は、pimplイディオムを使用してインクルードを抑えることができます。ただし、ポインタではなく型を使用する場合、コンパイラはそのサイズを知る必要があります。

編集:j_random_hackerはこの答えに重要な資格を追加します。基本的にはサイズはseを知る必要があるということですが、タイプを知るだけでよい場合は前方宣言を行うことができますexists、タイプへのポインターまたは参照を作成するため。 OPはコードを表示しませんでしたが、コンパイルできないと文句を言っていたので、私はOPがseを参照するだけでなく、タイプをしようとしていると(おそらく正しく)仮定しました。

11
tpdi

完全な#includesの前方宣言代わりを使用できるのは、not型自体(このファイルのスコープ内)ではなく、そのポインターまたは参照を使用する場合のみです。

型自体を使用するには、コンパイラはそのサイズを知っている必要があります-したがって、その完全な宣言を確認する必要があります-したがって、完全な#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 
6
Adi Shavit

私は同じ問題を抱えていましたが、異なるファイルの複数の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
2
Bill Kotsias

Bill Kotsiasが指摘したように、ポイントの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;
};
0
Timmmm

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;
0
Notinlist

@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
>>
{
};
0
Mark Lakata