ページ 11

[c++] テンプレートの型名について

Posted: 2013年11月20日(水) 13:57
by K_Tarou
お世話になっております、大変初歩的な質問かもしれませんがお願いします。
下記のサイト様を参考にイテレータとクラステンプレートの簡単な実装を試していてエラーが出たので、その理由について伺いたいのです。
http://program.station.ez-net.jp/specia ... r-make.asp

以下はヘッダファイル部分ですが、内容は至極単純なコンテナクラスとイテレータクラスをテンプレートにしただけのものです(200行近くあり冗長です、すみません)
エラーが出た場所は MyClassクラスの実装部分の "begin関数" と "end関数" の部分です。
► スポイラーを表示
コンテナであるMyClassクラスの "begin関数" と "end関数"の戻り値の部分で "型指定子がありません"等のエラーが出たので、
調べると、 "typedefだけではなく、typename指定をして型である事を明示する必要がある"という解決策らしい情報を得たので試したのですが、結果は変わらずエラーでした。


肝心の質問ですが、
begin関数、end関数共に戻り値を "iterator" から "MyClassIterator<T>" に変更すると意図通りにコンパイルが通るのは確認しましたが、
何故、typename指定した筈の "iterator" は戻り値の型として認められないのでしょうか?
色々、調べて試したのですが、理由が分かりません。どうかよろしくお願いします。

ちなみに環境は、VisualStudio C++ 2010 です。

Re: [c++] テンプレートの型名について

Posted: 2013年11月20日(水) 14:31
by usao
MyClass内のtypedefで typename を付けるのではなくて
begin()とend()の実装箇所の戻り値を

コード:

template<typename T>
typename MyClass<T>::iterator MyClass<T>::begin()
{ ... }
のようにすると通るのではないでしょうか…
ということでやってみたら,VS2012でコンパイル通りましたよ.

(少なくとも単にiteratorと書くのではなくて,
 MyClass<T>::iterator と書かないとだめだろう.
  ↓
 とおらねぇ.typename付けて型名だと明示しよう.
  ↓
 OK.いけた.
 という手順になったです.)

Re: [c++] テンプレートの型名について

Posted: 2013年11月20日(水) 14:41
by YuO
オフトピック
既にusaoさんが回答されていて被っていますが,投稿してしまいます。
(INCITS/)ISO/IEC 14882:2011 3.4.1 Unqualified name lookupに,iteratorをMyClass<T>の中から探す,というルールがないからだと思います。
一番関係しそうな¶8では,
INCITS/ISO/IEC 14882:2011 さんが書きました:A name used in the definition of a member function of class X following the function’s declarator-id or in the brace-or-equal-initializer of a non-static data member of class X shall be declared in one of the following ways:
と,「メンバ関数のdeclarator-idの後」についての記述ですし。
基本的に,識別子の走査は前から,ということを覚えておくのがよいと思います。
その時点で出てきていない名前空間/クラス等は,明示が必要です。
K_Tarou さんが書きました://begin関数は最初の位置を示すイテレータを作って返す
template<typename T>
iterator MyClass<T>::begin(){   //エラー
iteratorは,この時点ではMyClass<T>が名前を探す対象にないので,global namespaceのみから探されます。
typename MyClass<T>::iteratorのように修飾して,MyClass<T>のメンバであることをきっちりと示す必要があります。

Re: [c++] テンプレートの型名について

Posted: 2013年11月20日(水) 15:51
by K_Tarou
usaoさん
迅速なご回答ありがとうございます。
どこのクラスで宣言されているのかを記述しなくてはいけなかったのですね。
自分でコメントに " MyClass::iteratorとして使えるようにする " と書いておきながら、間抜けなミスを犯してしまってました。
仰る通りにソースを修正しましたら、無事コンパイルが通りました。かなり悩んでいたので本当に助かりました、ありがとうございます!



YuOさん
usaoさんと同じく、迅速なご回答ありがとうございます。
そもそも、走査対象になっていなかったということだったんですね、勉強になりました!
お話をまとめますと、

1. クラス内の宣言で typenameを付けて型であると明示しても、外からは型であるかは分からない(つまり再度、typenameを付けなければならない)
2. 実装の部分は外で行っている為、そのままでは識別子は外(グローバルな名前空間)からしか探されない

という解釈でよろしいでしょうか?
お二方共、大変分かりやすく、速い回答をありがとうございました!