バウンティの質問:したがって、これらの2つのFoo
sは同じものではありません。いいね2番目の形式はライブラリで提供されます。 変更できない場合、どうすればそれを前方宣言できますか?
繰り返し定義がなければ、CとC++は繰り返し宣言を許可するといつも思っていました。次に、Cライブラリを拡張するC++コードを記述しようとしたときに、この問題に遭遇しました。
struct Foo;
typedef struct {} Foo;
これにより、次のエラーが発生します。
「struct Foo」には「struct Foo」として以前の宣言があります
私は前向きに宣言したい、それをくそー!ここで何が問題になっていますか?
typedef-ing anonymous structは、C++ 03より前の慣例であり、主にC99以前のコンパイラとの互換性を維持することを目的としています。
これが2011年であり、C++とCの両方が変更されていることを考えると、そのようなライブラリの最新バージョンがないのはなぜでしょうか。
それが開発中でなくなった場合、「去る」ことはできませんが、「存続」して変更するだけです。まだ展開中の場合は、問題を開発チームに送信します。
回避策が必要な場合は、構造体が継承できることを考慮してください。したがって、次のようなフォワード宣言を書きます
struct MyFoo;
そしてそれを次のように定義します
#include "old_library.h"
struct MyFoo: public Foo {};
また、すべてのコードでFoo
を忘れて、常にMyFoo
を使用してください。
同じ名前の2つの異なるエンティティを宣言しています。最初、 struct Foo
はFoo
という名前の構造体です。 2番目はanonymous構造体のエイリアスです。
代わりに行う場合:
struct Foo;
struct Foo {};
両方の状況でFoo
という名前の構造体を宣言しているため、機能します。
匿名構造体を転送宣言することはできません。 2つの選択肢があります。定義全体を含めるか、ヘッダーを変更して構造体に名前を付けます。
同様の状況で、次のようなレガシーCヘッダーがあります
== old_library.h ==
typedef struct { int data; } Foo;
== /old_library.h ==
私は自分のC++クラスで、プライベートメソッドのパラメーターとして使用します。
class C {
void run(Foo *ds);
...
}
C.hppの#include "old_library.h"を回避するには、次の前方宣言を使用します。
class C {
struct Foo;
void run(Foo *ds);
...
}
c.cppには次のステートメントがあります。
extern "C" {
#include "old_library.h"
}
struct C::Foo : public ::Foo {};
この方法では、Fooの代わりにC :: Fooを透過的に使用し、MyFooは必要ありません。
C++では構造体をtypedefする必要はありません。
struct Foo; // Forward declaration
struct Foo
{
}; // Definition
Cでstruct Foo
の代わりにFoo
だけを呼び出す場合は、doが必要です。typedefもさまざまな方法で実行できます。
struct Foo; /* Forward declaration */
struct Foo /* The name is needed here */
{
}; /* Definition */
typedef struct Foo Foo; /* typedef */
または
struct Foo; /* Forward declaration */
typedef struct Foo /* The name is needed here */
{
} Foo; /* Definition and typedef combined */
もちろん、CとC++の両方でstruct Foo
という形式を使用できます。
前方宣言では、struct
というFoo
が存在することを宣言しています。
2番目の宣言は、typedef
というFoo
です。これらは同じものではありません。
私見、typedef
を
typedef struct Foo {} Foo;
^^^^^
害はなく、CとC++の両方で互換性があります。これで、それを転送宣言できます。
[注:typedef
にまったく触れないことを主張する場合は、ここにダーティトリックがあります。
struct Foo;
#define struct struct Foo
#include"Foo.h" // contains typedef struct {} Foo;
#undef struct
これは、Foo.h
には、struct
宣言が1つだけ含まれています。私お勧めしませんそれ。]
あなたの特定のコンパイラはここで違いを生むかもしれません。
MinGW GCC 3.4.5を使用すると、どちらの宣言もエラーや警告なしでコンパイルされます(-Wall
を使用)
struct Foo;
typedef struct {} Foo;
そして
struct Foo;
typedef struct Foo {} Foo;
前方宣言がライブラリ内にすでに存在することは可能ですか?たとえば、循環ポインタを許可するには:
struct Foo;
typedef struct Foo {
struct Foo *fooPtr;
} Foo;
これがライブラリヘッダー内にすでに存在する場合、説明したエラーが発生します。
Typedefの前方宣言の場合、次のようにtypedeffされているものを参照する必要があります。
struct foo;
typedef foo bar;
class foo{};
匿名構造体を前方宣言したいので、元のエンティティの前方宣言で名前を付けることも、型定義するときに参照することもできません。 「論理」構文は次のようになります。
struct ;
typedef bar;
class {};
しかし、これは明らかに不可能であるため、匿名の構造体を転送宣言することはできません。
標準化するために、9.1-2を見てみましょう。
クラスキー識別子のみで構成される宣言。現在のスコープ内の名前の再宣言、またはクラス名としての識別子の前方宣言です。クラス名を現在のスコープに導入します。
識別子なし、前方宣言なし。
つまり、本当に必要なアドバンテージを提供しない限り、匿名の構造体は避けてください。
私は最近、元のポスターと同じ問題に遭遇し、以下のように解決したと思います:
次のように定義されたサードパーティ提供のAPIのラッパーを書いています。
Foo.h:
typedef struct _foo
{
int i;
} Foo;
Foo* MakeFoo();
int UseFoo(Foo* foo);
私のラッパーはFooをメンバーとして持つ必要がありますが、ラッパーのすべてのコンシューマーにFooを公開したくありません。
UberFoo.h:
#pragma once
struct _foo; // forward declare the actual type _foo, not the typedef Foo
class UberFoo
{
public:
UberFoo();
int GetAnswer();
private:
_foo* f;
};
UberFoo.cpp:
#include "UberFoo.h"
#include "Foo.h"
UberFoo::UberFoo()
{
this->f = MakeFoo();
}
int UberFoo::GetAnswer()
{
return UseFoo(f);
}
これで、私のクラスのコンシューマは、_foo/Fooの実際の定義にアクセスしなくても、インスタンスを作成できます。これは、_fooへのポインターをパラメーターとして渡すか、関数からそれらを返す必要がある場合や、メンバー_fooを持つ場合にも機能します。
main.cpp:
#include <cstdio>
#include "UberFoo.h"
int main(int argc, char* argv[])
{
UberFoo u;
printf( "The Answer = %d\n", u.GetAnswer());
return 0;
}
ここでの秘訣は、typedefされた名前ではなく、実際の構造体型を前方宣言することでした。古いCコードでは一般的であるように、構造体が匿名でないことが重要であることに注意してください。
typedef struct // the actual struct type underlying the typedef is anonymous here
{
int i;
} ThisWontWork;
お役に立てれば!
前方宣言を避けてみませんか。
2番目の定義がヘッダーファイルにある場合は、最初にヘッダーファイルをC++ヘッダーファイルに含めることができます。 C++がそれをCヘッダーと見なすようにするには、extern "C" {
および}
で#includeを使用することで、ほとんどの場合十分です。
以前に使用した名前をtypedefしようとしています。ステートメントは完全に有効です。別の名前を使用する必要があるだけです。
struct Foo; // Forward declaration of struct Foo
typedef struct {} anotherFoo; // Another structure typedefed
struct Foo {
// Variables
}; // Definition of the forward declared Foo.
Typedefは同じ名前で使用できないことに注意してください。
名前が付いていないので、それを転送宣言することはできません。名前のない構造体で、Fooはtypedefです。