2016-10-26 14 views
18

は私がutilA.cppに次のコードスニペットを持っています:utilA.hがライン0にstruct tmを使用しているためであると思われるこれはC++の前方宣言ですか?

error: variable 'xm::tm time1' has initializer but incomplete type 

utilA.cppをコンパイルするときにGCCは文句
// utilB.h 
namespace xm 
{ 
    void zoo(struct tm timeval); //<-----line 0 
} 


// utilA.cpp 
#include <utilB.h>     //<----line 1 
#include <time.h>     //<----line 2 
namespace xm 
{ 
    void foo() 
    { 
     struct tm time1 = {0}; //<----line 3 
    } 
} 

time.hは含まず、コンパイラは0行目のstruct tmを前方宣言として扱います。したがって、0行目のヘッダの中にxm::tmとして解決されます。

したがって、C++標準では、struct tmを関数宣言の型としてforward宣言として定義していますか?これを説明するのを助けて、標準からの引用符が役立つでしょう。

+6

あなたのヘッダがそれに依存するので、あなたのヘッダに '#include 'と書いてください。 – molbdnilo

+0

はい、utilB.hに#include を追加する必要がありますが、これは巨大なプロジェクトのコードスニペットであるため、根本的な原因を見つける前に多くのことを混乱させました。 – ZijingWu

+0

これはプログラミングの非常に悪いスタイルです。それを無視します。 PS: '#include'-sを一番上に移動しようとしましたか? – i486

答えて

20

行0では、という名前のクラスが​​名前空間内に宣言されています。はい、C++では、関数/テンプレートパラメータで宣言型を使用できます。

N4140§3.4.4 [basic.lookup.elab]/2

詳述型指定子は、この検索が見つからないクラスキーと によって導入された場合以前型名を宣言し、または は型指定子を詳述場合は形と宣言して表示されます。

クラス-KE y属性指定子 - seq opt識別子;

詳細型指定子は、3.3.2で説明したように クラス名を導入する宣言です。

あなたは​​名前空間内のtmという名前のクラスを宣言しているので、それは名前の検索がライン3 ::tm(および::std::tm)にtmのために検出した最初の名前だとは見なされません。そしてクラス::xm::tmの定義がないので、コンパイラはそれが不完全な型であると不平を言う。

あなたがC++にCコードを書いていなかった場合は、

struct tm; 

namespace xz{ 
    void zoo(tm timeval); 
} 

または

#include <ctime> 

namespace xz{ 
    void zoo(tm timeval); 
} 

のようなものを書きたい、あなたはその問題を持っていないでしょう。

だから、C++標準では、前方宣言と関数の引数の型として、このstruct tmを定義しないあなたは、前方宣言することができないことを名前空間stdで名前

7

を覚えています。これを説明するのを助けて、標準からの割り当てを参考にしてください。

はい、struct tm timevalには、新しいクラス名xm::tmが導入されます。


(説明や引用符)

struct tm新しいクラス名を導入するために使用することができelaborated type specifier、です。

$3.1/4 Declarations and definitions [basic.def]

[注:クラス名は、暗黙的に([dcl.type.elab])精緻型指定子によって宣言することができます。 - エンドノート]

$9.1/2 Class names [class.name]

クラスキー識別子のみからなる宣言。現在のスコープ内の名前の の再宣言か、またはクラス名としての識別子の前方の 宣言のいずれかです。現在のスコープにクラス の名前を導入します。

$3.4.4/2 Elaborated type specifiers [basic.lookup.elab]

または精緻型指定子は 形態と宣言に表示されている場合:

class-key attribute-specifier-seqopt identifier ; 

詳述型指定子を導入宣言であります[basic.scope.pdecl]で説明されている のクラス名。

$3.3.2/7 Point of declaration [basic.scope.pdecl]

詳述型指定子は赤緯指定子-配列または名前空間スコープで定義された関数の パラメータ宣言節で使用される場合、 識別子が宣言されていますネームスペース内のクラス名として に宣言が含まれています。関数パラメータの宣言として使用struct tm timevalについて

<time.h>が含まれ、tmという名前のクラスがまだありませんされていないため、クラスtmは次にxm::tmが前方に宣言され、現在のスコープ(すなわち名前空間​​)内で宣言されるであろう。