dポイントプレゼントキャンペーン実施中!

テンプレート関数でコンパイルが通りません

いつもお世話になってます。テンプレート関数XXXで、引数のTYPE型によって、XXX内で呼び出す関数が変わります。以下の例では、eTypeがAならSetADataを呼び、eTypeがBならSetBDataを呼び出します。XXXのもうひとつの引数がテンプレート部です。本当は、rInfoの型(AInfoまたはBInfo)を判別できればeTypeは不要なのですが、判別の仕方がわからないので、eTypeでrInfoの型を伝えるようにしています。

template<typename T> int XXX( T& rInfo, const TYPE& eType )

if( eType == A ){
  SetAData( rInfo );
else if( eType == B ){
  SetBData( rInfo );
}
// 明示的インスタンス生成
template int XXX<AInfo>( AInfo& rInfo, const TYPE& eType )
template int XXX<BInfo>( Binfo& rInfo, const TYPE& eType )

上記のようにした時、コンパイラはTの部分をAInfoとBInfoの両方で解釈するので、どうしても以下のようなコンパイルエラーが出ます。

---
`int XXX(T&, const TYPE&) [with T = AInfo]':
error: no matching function for call to `SetBData(AInfo&)'
note: candidates are: int SetBData(BInfo&)

`int XXX(T&, const TYPE&) [with T = BInfo]':
error: no matching function for call to `SetAData(BInfo&)'
note: candidates are: int SetAData(AInfo&)

XXXをテンプレート関数でなく、明示的にAInfoとBInfoのオーバーロードにする手もあるかもしれませんが、XXXの中で、ここには載せていない大多数の部分は、まったく同じなので、テンプレート関数にするのが筋かなと思っています。このコンパイルが通るようにするには、どうすれはよいのでしょうか。

A 回答 (4件)

もしも、AInfo と BInfo が全く関連のない型であれば、 typeid で、クラス名を判別できますが……。



本当なら、オーバーロードが最適だと思います。

それも、この場合なら、XXX をオーバーロードするのではないです。
基本は、

class infoBase
{
virtual int XXX()
{
... いろいろな処理
setData();
... いろいろな処理
}

virtual void setData() = 0;
}

class AInfo : public infoBase
{
virtual void setData()
{ setAdata に相当する処理}
}

class BInfo : public infoBase
{
virtual void setData()
{ setBdata に相当する処理}
}

こんな感じで、XXX は、「論理的なひとつの関数」
setData は、「それぞれのデータに合わせて仮想化」
というのがシンプルで良いと思います。
    • good
    • 0
この回答へのお礼

ご回答、どうもありがとうございました。typeidというのがあるのですね。勉強します。データの方を継承クラスにする方法もあるのですね。今回は、AInfo とかBInfo は、中身が異なる小さな構造体なので、ここまではしない方針になりましたが、とても勉強になりました。

お礼日時:2010/09/14 19:35

ごめんなさい。

なんか勘違いしてた。NO1は無視してください。

さて、おっしゃるように、それぞれの処理の中で、双方同時に定義されていない関数を呼ぶと
コンパイルエラーになります。

解決策は「関数名を同じにすればよい」。
具体的には、次のソースの通りです。
#include <stdio.h>
class A{
public:
voidprint(){printf("A\n");};
};
class B{
public:
void print(){printf("B\n");};
};

void SetData(A){printf("SetA\n");}
void SetData(B){printf("SetB\n");};

template<typename T> int XXX(T& arg){
arg.print();
SetData(arg);
return 0;
};

int main(void){
A a;
B b;

XXX(a);
XXX(b);

return 0;
}

同名のメンバ関数を呼び出す、または引数が異なる関数を定義し、呼び出す。
質問者さんが書かれた、SetAData,SetBDataを、SetDataとすればたぶん全てがうまくいきます。
    • good
    • 0
この回答へのお礼

何度もご回答、どうもありがとうございました。おっしゃるとおり、データセット関数を同じ名前にすればよいのですね。

お礼日時:2010/09/14 19:31

SetAData、SetBDataがどんな関数かよくわかりませんが、



AInfo、 BInfo を 引数とするテンプレート関数 SetXDataを作る

もしくは、

AInfo を 引数とするSetXData関数
BInfo を 引数とするSetXData関数
を作る

ではだめでしょうか?
    • good
    • 0
この回答へのお礼

ご回答、どうもありがとうございました。よく考えてみると、おっしゃるようにSetXDataでまとめてしまってよいものでした。ここまで頭がまわらなくて…。

お礼日時:2010/09/14 19:30

キーワードは「テンプレートの部分特殊化」


以下、サンプルソースです。

#include <stdio.h>
typedef unsigned long long A;
typedef unsigned short B;
template<typename T> int XXX(T& arg){
printf("ノーマル\n");
return 0;
}
// 以下、特殊化
template<> int XXX(A& arg){
printf("A\n");
return 0;
}
template<> int XXX(B& arg){
printf("B\n");
return 0;
}
int main(void){
A a;
B b;
int c;

XXX(a);
XXX(b);
XXX(c);
return 0;
}
    • good
    • 0

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