• ベストアンサー

C++テンプレートクラスの内部クラスについて

テンプレートクラスについていろいろ試していたところ以下のようなコードで struct A {     struct AA { };     operator A::AA() { return A::AA(); } // (1) }; template<typename T> struct B {     struct BB { };     template<typename U>     operator B<U>() { return B<U>(); } // (2)     template<typename U>     operator typename B<U>::BB() { return typename B<U>::BB(); } // (3) }; int main() {     static_cast<A::AA>(A()); // (1) ok     static_cast<B<int> >(B<short>()); // (2) ok     static_cast<B<int>::BB>(B<short>()); // (3) compile error     return 0; } (1)と(2)はできて(3)だけがコンパイルを通りませんでした。 試したコンパイラはVC9とg++(3.3.4)とbcc32(5.5.1)で、VC9では以下のようなエラーをはきました。 「error C2440: 'static_cast' : 'B<T>' から 'B<T>::BB' に変換できません。     with [ T=short ] and [ T=int ] コンストラクタはソース型を持てません、またはコンストラクタのオーバーロードの解決があいまいです。」 (1)と(2)ができれば(3)のようなこともできそうな感じがしたのですが、他に書き方があるのでしょうか。 どなたかご存知の方がいらっしゃいましたらご教示お願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

 こんにちは。何度もすんません。  struct BBの中にダミーのenumを置いて、operator U()の中に其れを書けば、B<U>::BB以外のキャストをした時にコンパイルエラーを出させる事が出来ました。  此れにて筆を収めさせて頂きます。 struct B { struct BB{ enum{IsBB = 0}; }; //B<U>への変換を受け入れる template<typename U> operator B<U>(){ return B<U>(); } //(2) //以下でB<?>::BBである事を保障出来る template<typename U> operator typename U()//(3) { U::IsBB;//UがBBで無い時、ココでコンパイルエラーに出来る return typename U(); } //boolへの変換を受け入れる operator bool() const { return true; } //(4) }; static void test(const B<int>::BB&) { } int main() { static_cast<A::AA>(A());//(1) ok static_cast<B<int> >(B<short>());//(2) ok static_cast<B<int>::BB>(B<short>());//(3) ok static_cast<B<int>::BB>(B<int>());//(3) ok ::test(B<short>());//(3) ok ::test(B<int>());//(3) ok //以下の3つのキャストは認めてはいけない static_cast<int>(B<int>()); //(3) error static_cast<A>(B<char>()); //(3) error static_cast<A::AA>(B<long>()); //(3) error if(B<char>())//(4) ok { // } return 0; }

vapraip
質問者

お礼

御礼が大変遅くなってしまいすみません。 > 何度もすんません。 だなんてとんでもございません。とてもありがたい限りです。 逆に私の方が申し訳ない限りです・・・ なるほど、ちょっと強引かも知れませんがお答えいただいた方法で目的としていた機能は 実現できました。 感激です。ありがとうございます。 ・・・でもやっぱり(1)(2)は適合してくれて、なぜ(3)だけ適合してくれないのかが 気になるので質問内容を改めて再投稿してみます。 これまでの非常に丁寧なご回答大変ありがとうございました。 またお付き合いいただけるとうれしいです。

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

GCC だと「コピーコンストラクタとデフォルトコンストラクタのどっちを使うかわからん」という素敵なエラーなんですよね.... ちょっとこの辺は規格でも探し切れていません. とりあえず手元の GCC で確認した限りでは ・B<U>::BB に, B<T> を引数にするコンストラクタを作る ・B<T> で B<U>::BB をフレンド宣言する で逃げられるかもしれない.

vapraip
質問者

お礼

御礼が遅くなってしまい申し訳ございません。 ご回答ありがとうございます。 > B<U>::BB に, B<T> を引数にするコンストラクタを作る は、おそらく最初に machongola さんにご回答いただいたものだと思うのですが、 違っていたらすみません。あと私の質問内容が悪くてすみません。 もう一度質問内容を改めて再投稿したいと思います。 せっかく回答していただきながら大変申し訳ございません。

vapraip
質問者

補足

正確にはキャスト自体が目的ではなく(1)のような内部クラスへの型変換演算子と (2)のような他の引き数を持つテンプレートクラスへの型変換演算子は適合するのに、 その2つを組み合わせた(3)の他の引き数を持つテンプレートクラスの内部クラスへの 型変換演算子は適合しないということがどうにも納得がいかなかったのです。 ちなみに最初のものには書いていませんでしたが template<class T> struct B {     struct BB { };     operator typename B<T>::BB() { return typename B<T>::BB(); } // (4) }; の(4)ように同じ引き数を持つテンプレートクラスの内部クラスへの型変換演算子は 適合してくれました。 なのでどういうルールで適合してくれるのか、わからなくなってしまったのです。

回答No.2

 こんにちは。御礼頂きました。  其の後、チョッと試したのですが、operator B<U>::BB()とせず、ストレートにoperator U()とすれば適合する様です。  尚(2)(4)(5)が無いと全て(3)が使用されます。要は、operator U()だと何でもかんでも適合してしまいます。  なので、オーバーロードで型の特定を厳密化させて行き、なるべくoperator U()に適合するのを遅延させた方が良さそうです。  後、最後の最後までoperator B<U>::BB()が適合する事はありませんでした。因みにテンプレートx2パラメータを以ってしても不可能でした。  ↓コレでも無理  template<template<class>class X, typename U>  operator typename X<U>::BB() { return typename X<U>::BB(); } //一応出来たので参考程度に template<typename T> struct B { struct BB{}; template<typename U> operator B<U>(){ return B<U>(); } // (2) template<typename U> operator typename U(){ return typename U(); }// (3) operator typename B<T>::BB() { return typename B<T>::BB(); }// (4) operator bool() const { return true; } // (5) }; static void test(const B<int>::BB&) { } int main() { static_cast<A::AA>(A());//(1) ok static_cast<B<int> >(B<short>());//(2) ok static_cast<B<int>::BB>(B<short>());//(3) ok static_cast<B<int>::BB>(B<int>());//(4) ok ::test(B<short>());//(3) ok ::test(B<int>());//(4) ok if(B<char>())//(5) ok { // } return 0; }

vapraip
質問者

お礼

非常に丁寧なご回答ありがとうございます。

回答No.1

 こんばんは。  (3)には適合しない見たいです。  BBにB<T>の変換コンストラクタを書けばまかり通るようです。でも、何だか怪しい様な・・・。 template<typename T> struct B { struct BB { explicit BB(const B<T>& r){ } void TestMethod(){ std::cout<< "test method" << std::endl; } }; template<typename U> operator B<U>(){ return B<U>(); } // (2) //ココは適合しないらしい //template<typename U> //operator typename B<U>::BB(){ typename return B<U>::BB(); } // (3) }; int main() { static_cast<A::AA>(A());// (1) ok static_cast<B<int> >(B<short>());// (2) ok static_cast<B<int>::BB>(B<short>());// (3) ok static_cast<B<int>::BB>(B<short>()).TestMethod();// (4) ok return 0; }

vapraip
質問者

お礼

こんばんは。返事が遅くなりましてすみません。 なるほど内部クラスに変換コンストラクタを書いてあげればいいということですね。 ですがやはり(3)のように型変換演算子のオーバーロードで何とかすることは できないでしょうか。 というのも STL の auto_ptr の auto_ptr_ref のようなものを内部クラスにして 書くようなことはで出来ないものかと考えていたのです... せっかくお答えいただいたのに私の説明不足で申し訳ございません。 ですが型変換は出来ることがわかったので大変助かりました。 ありがとうございます。

関連するQ&A