最近テンプレートを勉強し始めました。
試しに次のような関数を書いたのですがコンパイルエラーが出ます。

template<class T>
void pirntAll(T t)
{
T::iterator p;
for(p=t.begin();p!=t.end();p++)
cout<<*p<<" ";
cout<<endl;
}

エラーメッセージを見るとT::iterator p;のところがダメらしく
pが定義されていないと叱られます。
結局本などを参考にして次のように書き換えました。

template<class InputIterator>
void printAll(InputIterator first,InputIterator last)
{
while(first!=last)
{
cout<<*first<<" ";
first++;
}
cout<<endl;
}

しかしprintAll()を使うとき1つめの定義ならprintAll(x);と書けますが
2つめの定義だとprintAll(x.begin(),x.end());と書かなくてはならないので
面倒です。そこで2つめの定義と次の関数を組み合わせることで、コンパイルも通り、
使うときもprintAll(x);と書けるようにしました。

template<class T>
void printAll(T t)
{
printAll(t.begin(),t.end());
}

一応問題は解決したのですが何かひどく冗長なことをやらされているようで
気分が悪いです。なんとか1つめのような書き方ができないものでしょうか。
または1つめの書き方が出来ない(T::iteratorが使えない)正当な理由が
あるなら教えてください。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

>なので「もしかしたら T が int かもしれない」という理由でコンパイルエラーはでないと思います。



確かに通りました(^^;

>また「もしかしたらTにまずいクラスが渡されるかも知れない」と言う心配はテンプレートを書くとき必要なんでしょうか。
>そんなことを言われたら全てのデータ構造に共通の処理しか出来なくなってしまうと思うのですが。

もしかして汎用のtemplate関数を書くのではなかったのでしょうか?
であれば最初の問題である「T::iterator pが通らない」は凄く簡単にコンパイルが通るように出来ますが・・・
渡す側のクラスをAとするとAのクラス宣言内でtypedef A* iterator;
とかしてやればtemplate内でT::iteratorがA::iteratorに変換されてちゃんと通ります(VC++ver6で確認済み)
    • good
    • 0
この回答へのお礼

VC++6では確かに通りました。!ありがとうございます。
実は今まで私が使っていたのはOSが Vine Linux2.0でコンパイラはgcc でやっていました。
その環境ではVC++でOKだったのと同じソースでコンパイルエラーを返して来ます。
ひょっとしてバージョンが古いとか,そういうことなのかもしれません。
ちなみにgccのバージョンは

$gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)

です。

この際、環境をWin&VC++に変えようか、と思っています。
ありがとうございました。

お礼日時:2001/02/26 16:58

templateはマクロではないのでプリプロセッサで置換されてからclassを評価するわけではなく、Tを汎用のものとして評価するはずです


そのときT::begin()が出た場合、汎用のもの(プリミティブタイプ、クラス、構造体など)が出た場合、T::begin()はint::begin()にもなりうるわけです。
これって宣言できませんよね?
なので設計の時点で間違ってるような気がします。

STLでは関数(Method)の内部に入ってからターゲットのiteratorを取る事はせず
引数で開始iteratorと終了iteratorを受け取るようにしているはずです。
なぜかというとtemplateの中では自分自身の宣言は参照できますが、汎用のタイプであるT::begin()は参照できません(Tがbegin()というメンバ関数を持つとは限りませんから)

たぶん
PrintAll()のtemplate内で
typedef T* T::iterator;
T::iterator T::begin()
{
// 適当に実装する;
}
T::iterator T::end()
{
// 同上
}

とでもしてやればコンパイルは通るかもしれません(未確認です)が、上記のメンバ関数begin()が定義されているか分からないのと同様の問題でT::begin()も正しい実装を書く事は出来ないはずです。(Tにintが渡された時を考えてみてください。int.hogehogeってあるはずの無いものですから)

という訳でPrintAll()関数の定義方法がSTLのiteratorにあってないのです

この回答への補足

Tがintにもなりうるからだめという説明がよくわかりません。
次のソースはOKでした。

class A
{
int a;
static void print(){cout<<"Hello A"<<endl;}
}

class B
{
int b;
static void print(){cout<<"Hello B"<<endl;}
}

template<class T>
void print(T t)
{
T::print();
}

main()
{
A a;
B b;

print(a);
print(b);
}

実行結果もちゃんと

Hello A
Hello B

とでました。

なので「もしかしたら T が int かもしれない」という理由でコンパイルエラーはでないと思います。
また「もしかしたらTにまずいクラスが渡されるかも知れない」と言う心配はテンプレートを書くとき必要なんでしょうか。
そんなことを言われたら全てのデータ構造に共通の処理しか出来なくなってしまうと思うのですが。

補足日時:2001/02/23 20:57
    • good
    • 0

T::iteratorが出来ない理由ですが


もし、templateにintなどのプリミティブタイプが渡された場合、
T::iteratorはどう解釈されるか考えてみてください
たとえばintを渡した場合、T::iteratorはint::iteratorとおきかえられて解釈されます
そのコードの前迄にint::iteratorが宣言されてなければ使えませんよね?
(iteratorはC++の言語仕様ではなくSTLで実装されたものでありtypedefで置き換えられたポインタである事が多いようです)

また、T::iteratorという表記ではTから置き換えられるnamespaceまたはTから置き換えられるクラス内の物でなければなりません

さらにC++コンパイラでは
 T::iterator p;
という式は変数、またはクラス宣言として受け取られるためT::iteratorはクラス、またはプリミティブタイプでなければ構文的に不正なものとなってしまいます

という訳でT::iterator以前に同じクラススコープ、またはnamespaceになる場所でtypedefでiteratorを宣言してやる必要があります


あ、あと内部でiteratorを使うのだからそのクラス内でbegin(),end()なども実装してやる必要があるでしょう

この回答への補足

>という訳でT::iterator以前に同じクラススコープ、またはnamespaceになる場所でtypedefでiteratorを宣言してやる必要があります

つまりどういうことでしょう? Tに渡すクラスの定義の中でiteratorを定義すればいいのでしょうか?
試しに次のようなクラスを作りましたがだめでした。

class Array10
{
public:
typedef int* iterator;
int table[11];
iterator begin(){return table;}
iterator end(){return table+10;}
};

ちなみにmainは次のように書きました。

main()
{
Array10 a;
for(int i=0;i<10;i++)a.table[i]=i;

printAll(a);
}

printAllのなかで T::iterator が Array10::iterator に置き換わっているなら動きそうなものですが。

それともprintAllのなかでT::iteratorを使う前にtypedefで宣言する必要があると言うことでしょうか。
しかしTがなにか分かるまでtypedefできないと思うのですが。つぎのような感じでしょうか。

template<class T>
void printAll(T t)
{
typedef ??? T::iterator;
T::iterator p;
for(p=t.begin();p!=t.end();p++)cout<<*P;
cout<<endl;
}

補足日時:2001/02/23 18:29
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qあの「冬ソナ」のペ・ヨンジュンが、、まさか、、

「冬のソナタ」が大好きでご多分にもれずペ・ヨンジュンさんのファンです。先日友人にヨン様の話をしたら彼女が「ペ・ヨンジュンはものすごい反日(抗日運動)主義者で最初の来日の時にはかなり過激な日本批判を発言したらしい」というのです。信じられませんでした。
もし本当だとしたらこの間、来日した時も彼の目に映る日本人ってどんなだったんだろうと考えこんでしまいました。
友人を疑う訳ではありませんがペ・ヨンジュンが反日主義者というのは本当の話なのでしょうか?

Aベストアンサー

ぺ・ヨンジュンにあまり興味が無いので、確かではないのですが…
この噂って、確か「冬ソナに出演していた女優さんと日本人ファンとのトラブルが
どういうわけか、ぺも巻き込んでしまっただけ。」というのを聞いた事があります。

○○(その女優@名前忘れた)に会える韓国ツアー!→実際会えなかった。→
○○は日本人が嫌いだから会わなかった(どこかの記事の推測)→
冬ソナの俳優は日本嫌い→「冬ソナ」=ペ→ペは反日主義。
という、変わった噂の流れだそうです(友人談)。
(注)友人は、芸能関係者では無いので、コレが正しいとは全くいえません。

まぁ、日本嫌い!という人はどこにでもいるし、♯3さんの仰るように、
自分の事を大切に思ってくれる人に対しては、国籍は関係ないと思います。
それよりも、ペの整形しまくり疑惑のほうが気になるなぁ…。

Qstd::cout << p と std::cout << *p の違

std::cout << p と std::cout << *p の違いは?

VC++でコードを書きながらC++を学んでいます。
ポインタで疑問に思ったことがあるので質問させて下さい。

int* p;
int n = 100;
p = &a;

上記のように変数を宣言・代入した場合、
std::cout << p と std::cout << *p のどちらでも"100"と表示されます。
これら二つの違いは何でしょうか?
本来*pとすべきところをpにしてもVC++が気を利かせて
&pのアドレスに入っているデータを表示してくれているということでしょうか?

Aベストアンサー

No.1氏の回答にあるコードを元に答えます。

>この場合&pでもアドレスが表示されると思うのですが、
>「&p」と「p」の違いは何でしょうか?
pはaのアドレス。
&pはpのアドレス。
(「p = &a」では、どこのアドレスを渡しているのか考えてみて下さい)


「&p」と「p」の違いというのが参照とポインタの違いを聞いているのだとしたら、constのポインタ==参照型で良かったと思います。
p = &a; //OK
&a = p; //error
int* const p2 = p;
p2 = &a; //error

Qペヨンジュン出演のドラマで

ペヨンジュン出演のドラマで冬のソナタ以外におすすめのものを教えてください。

Aベストアンサー

ヨンジュン氏の初期の「若者のひなた」もお勧めです。主役ではありませんけれど とても印象に残る存在でしたよ。一作ごと 色々な役をこなして 存在感のある 役者さんに変貌しているようですね。
特に「愛の群像」は韓ドラにしては丁寧で 大変重いストーリーでした。主人共ども すっかりはまりこんでしまい 私は 「冬ソナ」よりお勧めです。
NO3の方も書いておられるように「初恋」もお勧めです。彼の「冬ソナ」以前は家族を中心に どちらかというと 軽い作品より内容の濃い 作品を選んでいるような感じを受けます。一つのイメージに固執しないところが彼の 強みというか。 これから無限の可能性を感じさせてくれる稀な役者さんだと思います。
ただの流行の役者ではないことは確かだと思います。
作品は公式HPを調べれば 色々と分かりますよ。

Q{x = x>y ? x:y; return x;}

#include <iostream>
using namespace std;

inline int max(int x, int y){x = x>y ? x:y; return x;}

int main()
{
int num1, num2, ans;

cout << "2つの整数を入力して。\n";
cin >> num1 >> num2;

ans = max(num1, num2);

cout << "最大値は" << ans << "です。\n";

return 0;
}
の{x = x>y ? x:y; return x;}の部分の意味が解りません。

Aベストアンサー

inline int max(int x, int y){x = x>y ? x:y; return x;}
これを普通に関数で書くと

int max(int x, int y)
{
x = x>y ? x:y;
return x;
}

です。

x = 部分は右辺の結果が代入されます。これはわかりますよね。
x>y?x:y;
と書くと?より左にある条件式を判定し、その結果が真である場合は:で区切られた左側の値を、偽である場合は右の値を帰します。
x>yが真であればxを、偽であればyを返します。
それが、左辺値xに代入され、関数の戻り値として帰ります。

従って、2つの値をこの関数に入れると、大きいほうの値が帰ることになります。

Qペ・ヨンジュン

ペ・ヨンジュンは漢字でどうかくのでしょうか?
日本語読みも同じですか?

Aベストアンサー

アルファベットでは、一般的に
Bae YongJoon
になります。と、いうか韓国の公式ページもこのように表記しています。
'ぺ’は、発音としてはたぶん日本語の’ぺ’と’べ’のあいだくらいです。(単語の一番最初にくれば’ぺ’に近く、母音と母音の間にくれば’べ’に近いです。)
’ヨン’の’ン’は日本語の’りんご’の’ん’と同じなので’ng'、
'ジュン’の’ン’は普通に’n’の‘ン’です。

参考URL:http://www.byj.co.kr/

Qtemplate A(const T &t=T())

template<class T> A(const T &t=T());
という関数宣言において引数のところの解釈に戸惑ってます
どういう風に解釈したらいいのか教えていただければ幸いです

Aベストアンサー

引数 t は型Tのconstな参照体であり、
T()をデフォルトとする。
# 戻り値がありませんよー

class Foo {
public:
Foo();
Foo(int);
...
}

Foo f(5);
A(f);
A(); // = A(Foo()) と同じ

Qペ・ヨンジュン SONYハンディカムPC350の TVCMソング

以前、TVで見た、ペ・ヨンジュンさん出演の SONYハンディカムPC350の TVCMソングなんですが、、音のみで、ものすごいかっこいい音楽でしたが、、たしか「僕はハンディカム」とかペ・ヨンジュンさんは言っていたような。。このCMソングを探しています。どなたかご存知ではないでしょうか?

Aベストアンサー

CMオリジナル楽曲とのことです。
作曲者や演奏者については公開されていません。
もちろんCDもありません。

残念ながら既に終わったCFなので、
ソニーのサイトからは削除されています。
Googleのキャッシュにかろうじて残っていたので、
以下のURLを全て1行で入力して見てください。
http://66.102.7.104/search?q=cache:p2pM8VbZ_3AJ:www.sony.jp/products/Consumer/handycam/INFO/CM/dcr_pc350.html+%E3%83%8F%E3%83%B3%E3%83%87%E3%82%A3%E3%82%AB%E3%83%A0PC350+CM&hl=ja

Qvoid main(void){...}だとDosWindowが開くので

わざわざWindowsアプリにして以下のようにするしかないのでしょうか?

LONG WINAPI WinProcedure(HWND hW,UINT wM,UINT wP,LONG lP)
{
//ここに宣言を置く
switch(wM)
{
case WM_CREATE:
//ここに処理を置く
return 0;
default:
return(DefWindowProc(hW,wM,wP,lP));
}
}
WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
WNDCLASSwc;
HWNDhW,hPW;
MSGms;

wc.lpszClassName="goo";
wc.lpfnWndProc=(WNDPROC)WinProcedure;
wc.hInstance=hI;
wc.style=CS_HREDRAW|CS_VREDRAW;
wc.cbClsExtra=NULL;
wc.cbWndExtra=NULL;
wc.hIcon=LoadIcon(NULL,IDI_EXCLAMATION);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=NULL;
RegisterClass(&wc);
hW=CreateWindow
(
"goo",
"教えて!goo",
WS_OVERLAPPED,
0,
0,
640,
456,
NULL,
NULL,
hI,
NULL
);
ShowWindow(hW,nCS);
UpdateWindow(hW);
while(GetMessage(&ms,NULL,NULL,NULL))
{
TranslateMessage(&ms);
DispatchMessage(&ms);
}
return (ms.wParam);
}

もっと簡単にDosWindowが開かないようにする方法はないのでしょうか?
もしないとすると上記記述でもっと簡単にできないでしょうか?

わざわざWindowsアプリにして以下のようにするしかないのでしょうか?

LONG WINAPI WinProcedure(HWND hW,UINT wM,UINT wP,LONG lP)
{
//ここに宣言を置く
switch(wM)
{
case WM_CREATE:
//ここに処理を置く
return 0;
default:
return(DefWindowProc(hW,wM,wP,lP));
}
}
WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
WNDCLASSwc;
HWNDhW,hPW;
MSGms;

wc.lpszClassName="goo";
wc.lpfnWndProc=(WNDPROC)WinProcedure;
wc.hInstance=hI;
wc.style=CS_HREDRAW|CS_VREDRAW;
wc...続きを読む

Aベストアンサー

ウィンドウを開く必要がないなら、mainをWinMainに変更するだけで良いのでは? ウィンドウクラス登録、ウィンドウ作成、メッセージループ、ウィンドウプロシージャは全て不要な気がしますが。

WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
  //処理内容

  return 0;
}

Q【既婚男性限定】もしもあなたの奥さまが、ペ・ヨンジュンさんのおっかけになったら?

「ペ・ヨンジュン」で検索しても過去にはなかったので、あえて臆面もなく、伺わせてくださいませんか;もしも、あなたの奥さまが、ペ・ヨンジュンさんのおっかけになられたら、あなたはどうなさいますか? 賛成? 反対? それとも黙認? 並びに、もうすでにそんな奥さまをお持ちの男性方のご意見など拝聴できましたら、幸いです。よろしくお願いします。

Aベストアンサー

長文になります
 まさしくその真っ最中です^^私の妻は、最初(1年半位前ですかね~)はやはりヨン様狂になり、空港等へ追っかけることは無かったものの、内緒で通販でDVDや雑誌等買い込んでおりました。その金額、既に数十万!昨年、10~12月に入院生活を送りましたが、その間も続いていたようで、退院してきたら家の食器棚下の扉の中は韓国物だらけになっていました。その後はイ・ビョンホン⇒イ・ドンゴンと興味が変わったようですが、明後日には友人と「四月の雪」を観に行くようです。(チケットは私がオークションで探しました…)小5と小3の娘がおりますが、実は下の娘を妊娠したとわかってからは、ずっとセックスレスなのです。結婚してから上の娘を妊娠するまで約3年、猛烈に子供が欲しかった私達は、毎晩仕事の様に子作りに励みました。そのせいか、2人目が出来てからは、性的な興味が全くなくなってしまい、(他の女性にも)女房を女性と見る事もなくなってしまいました。かといって、粗末に扱うわけではなく、家内・娘達の事を第一に考えて生活しています。しかし、家内は割り切れないのでしょう。他の男性と浮気をするわけでもなく、女性として扱われなくなったと、時々漏らしています。(当然ですよね…)悪いとは思うのですが、40を目前にし、更に病気を患ってしまっている今、昔の様に構う気は起きません。よって、今の韓国にはまっている事は私にとっては助けでも有ります。楽しそうにしているので、「まあ、いいか」という感じですね。家事がややおろそかになってしまっている事には、最近少々閉口していますが… いずれブームも終わるでしょう。

長文になります
 まさしくその真っ最中です^^私の妻は、最初(1年半位前ですかね~)はやはりヨン様狂になり、空港等へ追っかけることは無かったものの、内緒で通販でDVDや雑誌等買い込んでおりました。その金額、既に数十万!昨年、10~12月に入院生活を送りましたが、その間も続いていたようで、退院してきたら家の食器棚下の扉の中は韓国物だらけになっていました。その後はイ・ビョンホン⇒イ・ドンゴンと興味が変わったようですが、明後日には友人と「四月の雪」を観に行くようです。(チケットは私が...続きを読む

Qint main()、void main()、void main(void)、int main(void)

今日、大学でC言語の講義の時間、先生が、

#include <stdio.h>

void main(void){

}

と宣言してプログラムを書くと教えていました。
main関数には、
main()
void main()
void main( void )
int main()
int main( void )

と、人によりいくつかの描き方があったりします。
どれが本当は正しいのでしょうか?
void mainはすべきではないとなんかの本で読んだのですが・・。

Aベストアンサー

通称C89という以前の言語規格(現行コンパイラの多くが準拠)では、下記のいずれかが正しい。
int main(int argc, char *argv[])
int main(void)

但し、最新のC言語規格(通称C99)では、
<ISO/IEC9899:1999>
or in some other implementation-defined manner.
</ISO/IEC9899:1999>
となっているので、処理系が戻り値のvoidを認めていればvoidも可。
# 組込み系などで戻り値を使わない環境もあるためでしょうか。

なので、コンパイラのマニュアルで戻り値のvoidにしていい/しろと書いてない限り、
voidは言語仕様的には正しくない。(でも動くものもある)


人気Q&Aランキング

おすすめ情報