アプリ版:「スタンプのみでお礼する」機能のリリースについて

テンプレートクラスについていろいろ試していたところ以下のようなコードで

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)のようなこともできそうな感じがしたのですが、他に書き方があるのでしょうか。
どなたかご存知の方がいらっしゃいましたらご教示お願いします。

A 回答 (4件)

 こんにちは。

何度もすんません。
 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;
}
    • good
    • 0
この回答へのお礼

御礼が大変遅くなってしまいすみません。
> 何度もすんません。
だなんてとんでもございません。とてもありがたい限りです。
逆に私の方が申し訳ない限りです・・・

なるほど、ちょっと強引かも知れませんがお答えいただいた方法で目的としていた機能は
実現できました。
感激です。ありがとうございます。


・・・でもやっぱり(1)(2)は適合してくれて、なぜ(3)だけ適合してくれないのかが
気になるので質問内容を改めて再投稿してみます。
これまでの非常に丁寧なご回答大変ありがとうございました。
またお付き合いいただけるとうれしいです。

お礼日時:2009/02/19 10:53

GCC だと「コピーコンストラクタとデフォルトコンストラクタのどっちを使うかわからん」という素敵なエラーなんですよね.... ちょっとこの辺は規格でも探し切れていません.


とりあえず手元の GCC で確認した限りでは
・B<U>::BB に, B<T> を引数にするコンストラクタを作る
・B<T> で B<U>::BB をフレンド宣言する
で逃げられるかもしれない.

この回答への補足

正確にはキャスト自体が目的ではなく(1)のような内部クラスへの型変換演算子と
(2)のような他の引き数を持つテンプレートクラスへの型変換演算子は適合するのに、
その2つを組み合わせた(3)の他の引き数を持つテンプレートクラスの内部クラスへの
型変換演算子は適合しないということがどうにも納得がいかなかったのです。

ちなみに最初のものには書いていませんでしたが

template<class T>
struct B {
    struct BB { };

    operator typename B<T>::BB() { return typename B<T>::BB(); } // (4)
};

の(4)ように同じ引き数を持つテンプレートクラスの内部クラスへの型変換演算子は
適合してくれました。
なのでどういうルールで適合してくれるのか、わからなくなってしまったのです。

補足日時:2009/02/19 11:02
    • good
    • 0
この回答へのお礼

御礼が遅くなってしまい申し訳ございません。

ご回答ありがとうございます。
> B<U>::BB に, B<T> を引数にするコンストラクタを作る
は、おそらく最初に machongola さんにご回答いただいたものだと思うのですが、
違っていたらすみません。あと私の質問内容が悪くてすみません。

もう一度質問内容を改めて再投稿したいと思います。
せっかく回答していただきながら大変申し訳ございません。

お礼日時:2009/02/19 10:59

 こんにちは。

御礼頂きました。
 其の後、チョッと試したのですが、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;
}
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/02/19 10:44

 こんばんは。



 (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;
}
    • good
    • 0
この回答へのお礼

こんばんは。返事が遅くなりましてすみません。

なるほど内部クラスに変換コンストラクタを書いてあげればいいということですね。

ですがやはり(3)のように型変換演算子のオーバーロードで何とかすることは
できないでしょうか。
というのも STL の auto_ptr の auto_ptr_ref のようなものを内部クラスにして
書くようなことはで出来ないものかと考えていたのです...

せっかくお答えいただいたのに私の説明不足で申し訳ございません。
ですが型変換は出来ることがわかったので大変助かりました。
ありがとうございます。

お礼日時:2009/02/17 20:57

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