ページ 1 / 1
スコープ演算子のミス?
Posted: 2009年10月24日(土) 01:50
by チルチル
World_cと言うクラスに
template<int Size>void Scene_Cursor(int X,int Y,int x,int y,int Insert,int (&Graph)[Size],char *Jump[/url],char *Back,int Return,int &Select);
と言うようなメンバ関数の宣言をして
template<int Size>void World_c::Scene_Cursor(int X,int Y,int x,int y,int Insert,int (&Graph)[Size],char *Jump[/url],char *Back,int Return,int &Select){・・・
のようにスコープ演算子で定義したところ
Menu.obj : error LNK2001: 外部シンボル ""public: void __thiscall World_c::Scene_Cursor<7>(int,int,int,int,int,int (&)[7],char * * const,char *,int,int &)" (??$Scene_Cursor@$06@World_c@@QAEXHHHHHAAY06HQAPADPADHAAH@Z)" は未解決です。
と言うようなエラーが出ました
未解決と言っているので多分スコープ演算子の使い方が間違っている気がします
この使い方が載っているサイトが無かったので質問させて頂きたいのですが
やはりスコープ演算子の使い方が間違っているのでしょうか?
環境は「Microsoft Visual C++ 2008 Express Edition」です
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 02:32
by 御津凪
テンプレートメンバ関数の宣言と定義は同じヘッダファイルにありますか?
現在のほとんどのコンパイラはテンプレート関数の外部(分割)定義をサポートしていません。
つまり、テンプレート関数を外部(ソースファイルに単独)で定義していると、
リンク時にテンプレート関数の対応づけがなされずに上記エラーが発生します。
これを回避するには、ヘッダファイルにテンプレート関数を定義するか、
テンプレートクラスの定義後にそのテンプレートメンバ関数を定義したソースファイルをインクルードする(もちろんそのソースファイルはビルドから外す)必要があります。
一応分割定義できないこともないですが、下記のURLで書かれている覚書のように、酷いことになります。
覚書(1)---テンプレートの宣言と定義を分けて書いた場合の憂鬱
ttp://www.is.oit.ac.jp/~club/~hxs/?%B3%D0%BD%F1%281%29---%A5%C6%A5%F3%A5%D7%A5%EC%A1%BC%A5%C8%A4%CE%C0%EB%B8%C0%A4%C8%C4%EA%B5%C1%A4%F2%CA%AC%A4%B1%A4%C6%BD%F1%A4%A4%A4%BF%BE%EC%B9%E7%A4%CE%CD%AB%DD%B5
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 05:21
by Eeel
おはようございます。
御津凪さんのリンク先、オーバーロードみたいな事になっちゃってますね。
オーバーロードよりも何かメリットがあるのか、
それともそういう酷さの例なのでしょうか。
私もテンプレートには苦労しました。
その質問をさせて頂いた時のアドレスです。
http://www.play21.jp/board/formz.cgi?ac ... &rln=40842
テンプレート関数ではなくて、テンプレートクラスなのでそのままは当てはまらないかもしれません。
テンプレートクラスは.cppで明示的インスタンス化をする事で分割できました。
http://d.hatena.ne.jp/umonist/20080730/p3
こちらは自分で検索していた時に見つけたテンプレート関数に関するページです。
テンプレートクラスではなかったので実際に試してはいませんが
お役に立つかもしれないので貼っておきます。
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 12:46
by チルチル
ヘッダとソースに宣言と定義を分けられなかったんですね・・
とりあえず
http://d.hatena.ne.jp/umonist/20080730/p3
のサイトを参考に
template void World_c<int Size>::Scene_Cursor(
template void World_c::Scene_Cursor<int Size>(
と書いてみましたがコンパイルが通りません
また何か間違えているのでしょうか?
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 13:10
by ねこ
サイトざっと目を通しただけなんだけど、その関数の処理内容がcppにあったら他の個所ではその関数の定義(ヘッダファイルとかの「void A();」のみしか見えないから実態が分からないよって意味じゃない?
TEST.cpp
void A() { int a = 0; };
TEST.h
void A();
MAIN.cpp
テンプレート A
にするとMAIN.cppのテンプレートではAの実態処理が分からないから
そういう使い方したかったらTEST.hに
void A() { int a = 0; };
こういう処理まで書かないとだめなんですよ、って解説じゃないかな。
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 13:15
by Eeel
>ヘッダとソースに宣言と定義を分けられなかったんですね・・
いえ、分けられると思います。
そして
http://d.hatena.ne.jp/umonist/20080730/p3
は分ける方法です。
(テンプレートクラスは分けられてテンプレート関数は分けられないが正解、なんて事だったらごめんなさい)
template.cpp ← テンプレート関数の定義
main.cpp ← テンプレート関数を<int>と<short>で呼び出す
という設定で話します。
<int Size>の部分はコンパイル時に適切な型に置き換わります。
template.objができた時点ですでに置き換わっているのですが、
template.cpp内だけからはどの型として使われているのかわかりません。
なので<int>や<short>の型の関数は作られず、リンク時にエラーが発生します。
その対処法の一つとして、template.cpp内で明示的にインスタンス化を行い
<int>や<short>の型の関数を作ってしまう、というのが私のやった方法です。
宣言と定義を分けないのならあのサイトの内容は忘れて、
.h内に定義も書いてしまえば動くと思います。
追記です。
>template void World_c<int Size>::Scene_Cursor(
>template void World_c::Scene_Cursor<int Size>(
>と書いてみましたがコンパイルが通りません
この部分は実際にインスタンス化するのが目的なので
<int Size>ではなくて具体的な取り得る数値を入れます。
取り得る数値の数だけインスタンス化します。
Sizeに当たる数値が1,3,5だったとすると
template void World_c::Scene_Cursor<1>(hoge);
template void World_c::Scene_Cursor<3>(hoge);
template void World_c::Scene_Cursor<5>(hoge);
という具合です。
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 13:17
by ねこ
あ、前半だけ読んでたから読み違ってた。 前レスはスルーして下さい。
Re:スコープ演算子のミス?
Posted: 2009年10月24日(土) 13:41
by チルチル
ああ、なるほど明示的なインスタンス化をしていたんですね
しかし<float>とか<int>なら別々にインスタンスしても問題ないですが
<int Size>は配列の要素数なので別々にインスタンスするぐらいなら引数で渡した方が良いですね・・
テンプレートの宣言と定義を分けると毎回こういう問題が出てくるんですね・・早めに知って良かったです
宣言と定義は必ず分けるようにしているのでテンプレートを使っても
全部オーバーロードみたいになってしまいますね・・
中身を書く手間は省けてもテンプレートを使わなくて済む努力をした方が良さそうです
結局スコープ演算子は関係無かったですね・・とんだ勘違いをしてしまいました
要素数を引数で渡したらコンパイルが通りました、皆様ありがとうございます