無名structの前方宣言

[戻る]
ホウジョウウサギ 2012/02/10(金) 16:08:25
使用しているライブラリのヘッダに

typedef struct
{ ... }
SHoge;

のように宣言された構造体があるのですが…


(1)このような無名の?構造体を前方宣言することは可能でしょうか?


(2)もし不可能であるなら,これを可能とするために
typedef struct SHoge
{ ... }
SHoge;
のようにヘッダを書き変えてしまっても問題ないのでしょうか?

しま 2012/02/10(金) 17:40:58
typedef の使い方は
typedef [(<型宣言>|<型名>)] <型の別名>
だと思うので

無名の構造体の前方宣言の意味がよくわかりません。
構造体にタグ名がないことが気になるということですか?

>typedef struct {...} SHoge;

は struct {...} と書く代りに SHoge と言替えて使えますと言っているのだと思いま
す。

仲澤@失業者 2012/02/10(金) 17:46:44
タグなしですね。迷惑なので自分とこでは使用禁止(笑)。

(1) ポインタなら可能かもしれません。
   struct SHoge; // 不完全型
   typedef struct FOO{
      SHoge *   m_Hoge;
   }FOO;
(2) 元のソースがいじれるなら、そのように変更したほうが
  色んな場面で平和です。自分は見つけたら即修正してます。

ちなみにタグありだがtypedefで書かないのも禁止、
タグと型名は必ず同一に強制。
だって面倒なんだもん(vv;)。

tetrapod 2012/02/10(金) 21:28:46
(1) できない : ISO/IEC 14882:1998 / JIS X 3014:2003
9.1-2 単に " <クラスキー> <識別子> ; " で構成される宣言は<snip>事前宣言とする。
# forward declaration の別訳としては先行宣言とか前方宣言とか。
なので名前がない=識別子のないクラスは事前宣言できない。
実際問題として struct; と書けたとしても、プログラマもコンパイラも解釈に困る。

(2) 問題なし : 同 ISO/JIS より
7.1.3-2 typedef 指定子を使って<snip>かつて参照していた型を再参照してよい。
例 : typedef struct s { /*...*. } s;

無名 struct や無名 class はコンストラクタ・デストラクタを記述するすべがないので
C++ に限定するなら、邪悪につき排除すべき存在と考えていい。
ウチでも無名 struct/class は使用禁止。

ホウジョウウサギ 2012/02/13(月) 14:30:32
皆様,回答いただきありがとうございます

(1)に関しては,そのままでは前方宣言できない ということですね.

(2)について…質問が言葉足らずだったかもしれません.
   あるlibを使うにあたって,それをビルドしなおすこと無しに
   公開されているヘッダだけをそのように書き換えて使ってしまっても問題ない,とい
うことなのでしょうか?
   (structのメンバ内容が同一であれば型名は変わってしまってもよい!?)

PATIO 2012/02/13(月) 15:31:24
ライブラリの管理が自分のところではなく、
別の部署、もしくは別の会社でライブラリ提供されていると言う話なら
修正しちゃ駄目だと思います。

文法的な話もさることながら品質保証と言う観点から考えると
ヘッダーファイルを修正した段階で品質保証外と言う話になると思うので。
ビルドが通るから良いとかそういう話とは次元が違う話だとは思いますけれど。

ただ、自分の所の管理対象ならヘッダーファイルを修正したのなら
リビルドするべきだと思うのでなぜそういう質問になるのかがちょっと分からないです。

他の所の持ち物で修正要求が出来ないのであれば、
提供されたものでつかえる範囲の中で使うしかないのではと言うのが
私の意見です。

仲澤@失業者 2012/02/13(月) 15:41:44
>(structのメンバ内容が同一であれば型名は変わってしまってもよい!?)

ごめん、やってみてください。

予測される問題の全てのケースについて網羅的に
解説するのはつらすぎます(前提条件も完全に明確とは言えないし)。
発生した問題について回答するほうを選びたいんですけど・・(vv;)。

ロマ 2012/02/13(月) 16:32:41
依存関係を減らすために、前方宣言を積極的に使うのは賛成です。

ラッパーをつくるのはいかがですか。

struct MyWrapper
{
  SHoge Data;
};

あるいは、以下でもいいのかなぁ。
struct MyWrapper : public SHoge
{
  MyWrapper();
  MyWrapper(const SHoge&);
  MyWrapper& operator = (const SHoge&);
};

PATIO 2012/02/13(月) 18:08:08
どうしてもやりたいならラッパーを作成と言う話に一票。

提供された物を改変するのではなくてラッパーで対応するのが良いと思います。

tetrapod 2012/02/13(月) 18:09:04
この例では SHoge という [構造体名] は存在しない。
[ある特定無名構造体] の別名 SHoge があるだけである。

無名構造体の事前宣言はできない (無名構造体の定義は可能だが)
事前宣言だけでは派生させることもメンバに含むこともできない。

つーことであとは PATIO 氏 02/13 に話は帰着してしまう。
自分でリスクを負って動作保証するのならご勝手にどうぞ。

無名構造体と有名構造体とでは、関数の引数として使うと動作が変わるよ
typedef struct T1 { ... } T2;
void func(T2); --- 実際に使われる名前は T1 である
生成されるアセンブララベル名前は _Z4func2T1 とか。

typedef struct { ... } T3;
void func(T3); --- 他に識別手段が無いので _Z4func2T3 となる

ホウジョウウサギ 2012/02/14(火) 10:01:50
[[解決]]
>ラッパー
ありがとうございます.
 例えばラッパーMyWrapperの宣言をWrapper.hに記述したとすれば,
 typedef struct {...} SHoge;
 が宣言されているヘッダを,このWrapper.hでincludeし,
 MyWrapperの詳細(SHoge)が必要な個所だけでWrapper.hをincludeすればよい
…ということですね.
この方法で困っている状況を改善できそうなので試してみます.


>なぜそういう質問になるのかがちょっと分からないです。
すみません.
激しく混乱しておりました.恥ずかしい限りです.
皆様,ご迷惑をおかけしました.

ITO 2012/02/14(火) 10:14:28
うーーん、
 何らかの演算用の関数(サブルーチン)で多用するところなら無名構造体も
ありかもしれませんがそのソフト固有の機能のための構造体には有名構造体をすすめま
す。
 特にチームでソフトを製作しているときに、無名構造体を使っているとあまり主張が
出来なくなると思いますし、どこかでバグの原因になると思います。
僕は変数はクラスよりも構造体でまとめるのが多いです。
有名構造体にしてバグが修復できた件も多々にあります。

ホウジョウウサギ 2012/02/14(火) 12:08:20
>ITO様
今回使用しているライブラリは自分や身内が作っているものではなく,
オープンソースのライブラリを利用していて
そこに無名の構造体があってちょっと困っているという状況です.
(なのでライブラリのリビルド自体は不可能なわけではないのですが,
 そうするなら,コードを共有するためには
 周囲の全員がそうしなければならないので避けたい)

私自身が,わざわざ無名の構造体を作ることを考えているわけではありません.
(無名にする理由(利点?)がわからないので…)

ITO 2012/02/14(火) 13:38:08
>  今回使用しているライブラリは自分や身内が作っているものではなく,
> オープンソースのライブラリを利用していて
> そこに無名の構造体があってちょっと困っているという状況です.
 失礼しました。
公開していて無名なのは問題ですね。
 ラッパーという話と重なってしまうかも知れませんが、DLL化してしまうてはないです
か?

ロマ 2012/02/14(火) 13:38:20
規格制定前の古い本、ARM(原著出版年1990) 9章(トッパンの訳本 p.207)から引用

"名前のないクラスの構文は主に、Cの構造
     typedef struct { /* ・・・ */ } mystruct;
 で使用されるが、これはC++の構造
     struct mystruct { /* ・・・ */ };
と等価である。"
 
なので、伝統のあるコードの中には、
古語が含まれているのかもしれませんね。

古いスレッドには追加発言できません。