• ベストアンサー

templateにの指定に従ったswitch

以下のような感じで、template TTの種類によって処理を変えたいのですがうまくいきません。 どの様にすればいいのでしょうか? 宜しくお願いします。 template<class TT> void vector3<TT>::GetMemberList(char *str,const int bufsize,char *format=0){  int i,j;  if(!format){   switch(TT){    case int:     format=new char("%d");     break;    case double:     format=new char("%lf");     break;   }  } }

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

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

 こんばんは。  まぁ、やり方は色々有りますが、ダイナミックなやり方なら、 (1)RTTIにスイッチを有効にして<typeinfo.h>をインクルードするtypeid()で型を比較する //此れをインクルードする必要がある #include<typeinfo.h> template<class TT> void vector3<TT>::GetMemberList(char *str,const int bufsize,char *format=0) { //あるので処理しない if(format)return; //選択された書式を受け取る const char* sz = 0; //typeid()で型比較 if(typeid(TT) == typeid(int)) { sz = "%d"; } else if(typeid(TT) == typeid(double)) { sz = "%lf"; } else { return;//該当しなければ引き返すしかない } //割り当てて複写 format=new char[::strlen(sz) + 1]; ::strcpy(format, sz); } (2)テンプレートでもって特殊化を行う(RTTIと<typeinfo.h>は必要なし) //int型、double型以外はココがコンパイルされてエラーになる template<class TT> class select_string { public: static const char* get_format(); }; //int型用 template<> class select_string<int> { public: static const char* get_format(){ return "%d"; } }; //double型用 template<> class select_string<double> { public: static const char* get_format(){ return "%lf"; } }; template<class TT> void vector3<TT>::GetMemberList(char *str,const int bufsize,char *format=0) { //あるので処理しない if(format)return; //書式の文字を受け取る。コンパイルの時点でケリが付いている const char* sz = select_string<TT>::get_format(); //割り当てて複写 format=new char[::strlen(sz) + 1]; ::strcpy(format, sz); }  と言った具合でしょう。

coronalith
質問者

お礼

なるほど、typeinfoは便利そうですねー。 どうも有り難うございました。

その他の回答 (1)

回答No.1

たとえばこんなの。 #include <iostream> using namespace std; void f(int) { cout << "f<int>()\n"; } void f(double) { cout << "f<double>()\n"; } template<typename TT> void f() { f(TT()); } int main() {   f<int>();   f<double>(); }

coronalith
質問者

お礼

なるほど、有り難うございました。

関連するQ&A

  • typeidと計算コスト

    今、以下のようなクラスの関数を作っているのですが、typeidはプログラム実行時に実行される関数という扱いなのでしょうか? それとも、コンパイル時に実行されるマクロ関数的な扱いのものなのでしょうか? もし、プログラム実行時に実行されるなら、コンパイル時にTTの種類によって内容をコンパイルする内容を変更すると言うことは不可能でしょうか? また、どうしても、プログラム実行時にしかできないのならと考え、 type_info ty=typeid(TT) と、代入してから判定してみようかとやってみたのですが、「error C2248: 'type_info::type_info' : private メンバ (クラス 'type_info' で宣言されている) にアクセスできません。」と表示され無理なようでした。 何か良い方法はないものでしょうか? template<class TT> class vector3{ public:   enum{NUM=3};   TT x[NUM];   int GetMemberList(char *str,const int bufsize,char *format=0); }; template<class TT> int vector3<TT>::GetMemberList(char *str,const int bufsize,char *format=0){   int i,j;   if(!format){     const int size=4;     type_info     format=new char[size];     if(typeid(TT)==typeid(int)){       strcpy_s(format,size,"%d");     }     else if(typeid(TT)==typeid(double)){       strcpy_s(format,size,"%lf");     }     else{       return(1);     }   }   j=sprintf_s(str,bufsize,format,x[0]);   for(i=1;i<NUM;i++){     j+=sprintf_s(str+j,bufsize-j,",");     j+=sprintf_s(str+j,bufsize-j,format,x[i]);   }   if(format)delete [] format;   return(0); }

  • コンパイルエラー: LNK2001

    今、ベクトル計算を簡単にするクラスを作ってみようとしています。 //vector3.h template<class TT> class vector3{ public:   enum{NUM=3};   TT x[NUM];   void set(const TT *vv)void set(const TT *vv){     int i;     for(i=0;i<NUM;i++){       x[i]=vv[i];     }   } }; のように、set関数をクラスの中に書いていると問題無いのですが、以下のように、 //vector3.h template<class TT> class vector3{ public:   enum{NUM=3};   TT x[NUM];   void set(const TT *vv); }; //test.cpp #include"vector3.h" template<class TT> void vector3<TT>::set(const TT *vv){   int i;   for(i=0;i<NUM;i++){     x[i]=vv[i];   } } と、cppファイルの中に書き換えると以下のようにエラーが出るようになります。 error LNK2001: 外部シンボル ""public: void __thiscall vector3<double>::set(double const *)" (?set@?$vector3@N@@QAEXPBN@Z)" は未解決です。 fatal error LNK1120: 外部参照 1 が未解決です。 これはいったい何故なのでしょうか? 使用しているのはVisualC++2008ExpressEditionです 宜しくお願いします。

  • 可変引数をconstで参照渡し

    以下のようなクラスをconstの参照渡しでうけとる、可変引数を持つ関数を作りたいのですが、以下のようにしてもうまくいきません。 何か良い方法はないものでしょうか? template<class TT> class vector3{ public:  enum{NUM=3};  TT x[NUM];  void Sum(const int num,...); }; template<class TT> void vector3<TT>::Sum(const int num,const ...){  int i,j;  va_list list;  va_start(list,num);  for(i=0;i<NUM;i++){   x[i]=va_arg(list,&vector3<TT>).x[i];  }  for(j=1;j<num;j++){   for(i=0;i<NUM;i++){    x[i]+=va_arg(list,&vector3<TT>).x[i];   }  }  va_end(list); }

  • switchとメモリ取得位置

    #include <stdlib.h> #include <string.h> #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE -1 char* get(char **p_str); char *get_line(char buf[]); int comp_rtn(const void *p1, const void *p2); typedef struct { int number; char class_type[10]; char name[15]; char subject[10]; int ten; } my; my *data; void myswap(my *p, my *q); int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufFormat; char *bufG; bufG = (char *)malloc(1000); if(bufG == NULL){ printf("メモリ不足"); free(bufG); } int line2 = 0; if((fp=fopen("jjj.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); if((fp=fopen("jjj.txt","r"))==NULL){   printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); if(data == NULL){ printf("メモリ不足"); free(data); } while(fgets(buf,1000,fp) != NULL){ bufFormat =(char *)malloc(strlen(buf) + 1); if(bufFormat == NULL){ printf("メモリ不足"); free(data); } bufFormat = get_line(buf); str = bufFormat; while(*str != '\0'){ bufG = get(&str); switch(field){      case 0: data[line].number = atoi(bufG); break case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; case 4: data[line].ten = atoi(bufG); break; } str++; field++; } line++; field = 0; } fclose(fp); qsort(data,line,sizeof(my),comp_rtn); for(int m = 0; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject); printf("%d\n", data[m].ten); printf("\n"); } free(data); return 0; } void myswap(my *p, my *q) { my temp; temp = *p; *p = *q; *q = temp; } char *get(char **p_str) { int i; char *str; str = *p_str; static char bufG[1000]; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else if(*str == '\\'){ str++; if(*str == 'c'){ bufG[i] = ','; } else if(*str == '"'){ bufG[i] = '"'; } } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; *p_str = str; return bufG; } char *get_line(char buf[]) { int in_quotation = FALSE, i = 0; char* str = buf; static char bufG[1000]; while(*str != '\0'){ if(*str=='"'){ if(in_quotation == TRUE){ str++; if(*str == '"'){ bufG[i] = '\\'; i++; bufG[i] = '"'; i++; } else{ in_quotation = FALSE; bufG[i] = *str; i++; } } else{ in_quotation = TRUE; } } else{ switch(*str){ case '\n': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'n'; i++; } else{ bufG[i] = *str; i++; } break; case ',': if(in_quotation == TRUE){ bufG[i] = '\\'; i++; bufG[i] = 'c'; i++; } else{ bufG[i] = *str; i++; } break; default: bufG[i] = *str; i++; } } str++; } bufG[i] = '\0'; return bufG; } 構造体メンバをポインタで宣言する方法はもうできていて 配列の方も組んでいるのですが 比較関数など所々省いてますがこのプログラムに対し以下のことをいわれました 1,switch文のfieldの値を数字じゃなく分かりやすいのに変えよ 2,mainのすぐしたの bufG = (char * )malloc(1000)が なかなか使用されないのにここでメモリを取るのはおかしい 3,これを使うまでの間にエラーが発生したときのfreeがない と言われました。 1ですが確かCではswitch文のcase式は整数型定数でなければならない とあるので無理な気もするのですが、方法ありますか? 2に関してはよくわかりません。効率がよくないのでしょうか? どの場所がいいのでしょうか 3に関してはどういうことなのかもわかりません。 この3点について教えて下さい。

  • C++にてtemplateで受け取った任意の型の変数が何型であるかを判定したい

    環境:VisualStudio2005, WinXP 以下のようなことは可能でしょうか? ・ある型の変数をそれが何型であるかを判定→例えばintとかcharとかchar *とか 概念としてはこんな感じです。 template<class Type> void func( Type a ) {   // 型を判定   switch( GetTypeChack(a) ){   case BOOL:   case INT:   case CHAR:   case FLOAT:     ・     ・   } }

  • C++の関数テンプレートで分からないところがあります。

    C++の関数テンプレートで分からないところがあります。 C++の入門書を読んで勉強しているのですが、その演習問題(答えはついてないです)で、以下のような問題がありました。 ----------------------------------------------------- 配列の全要素の最小値を求める関数テンプレートを作成せよ。 teplate <class Type> Type minof(const Type x[], int n); という形で作ること。 なお、最も小さい文字列を求められるようにするために、const char *型に明示的に特殊化したものも合わせて作成すること。 ------------------------------------------------ という問題なのですが、これにたいして僕は以下のように答えました。ヘッダのインクルードなどは省きます。 template<class Type> Type minof(const Type x[], const int n) {     int min = 0;     for(int i = 1; i < n; i++)         if(x[min] < x[i])             min = i;     return x[min]; } template<> const char* minof<const char *>(const char x[][64], const int n) {     int min = 0;     for(int i = 1; i < n; i++)         if(strcmp(x[min], x[i]) < 0)             min = i;     return x[min]; } int main() {     const int n = 5;     int a[n];     char s[n][64];     for(int i = 0; i < n; i++){         cout << i + 1 << "番目---";         cin >> a[i];     }     cout << "文字列\n";     for(int i = 0; i < n; i++){         cout << i + 1 << "番目---";         cin >> s[i];     }     cout << "整数の最小値---" << minof(a, n) << "です\n";     cout << "文字列の最小値---" << minof<const char *>(s, n) << "です\n"; } これをコンパイルすると、エラーで 明示的な特殊化; 'const char *minof<const char*>(const char [][64],const int)' は関数テンプレートの特殊化ではありません と 'minof' : 1 番目の引数を 'char [5][64]' から 'const char *const []' に変換できません。 とでてしまいます。 色々探してみたのですが、解決できませんでした・・。 特に最初のほうのエラーがよくわかりません。ちゃんと特殊化してる気はするのですが・・。 間違っている箇所の正当を載せていただけるとわかりやすくて、ありがたいです。 よろしくお願いします!

  • switch文について

    switch文の、switch(a)←このaの部分について分からない事があります。 例) void WRITE(void){ char str; fgets(str,8,stdin); puts(str); swicth(str){ case ??:実行文1;break; case ??:実行文2;break; ・ ↑    ・    default:break; } } としたとき、矢印の「??」の部分には文字列を指定することが可能でしょうか? 例えば、「RX」が入力されたら実行文1、「TX」が入力されたら実行文2・・・というようにしたいのですが、どう指定したらいいのかがわかりません。一文字だけなら「''」で囲むのはわかるのですが、文字列となると・・・ どなたかご教授願えませんでしょうか?

  • switch文で文字を比較することは出来ませんか?

    switch文で文字を比較することは出来ませんか? 例えば… int main(void){ char buf[5]; buf = 'b'; switch(buf){ case 'a': ・  ・  ・  break; case 'b': ・  ・  ・  break; }

  • C++での戻り値について

    C++で以下のソースを書きました。 どうしてaaaは問題ないのにbbbはだめなのかがわかりません。 どちらも、func1()、func2()で設定した文字列・vectorのポインタを返したいです。 int main() { const char* aaa = NULL; std::vector<const char*>* bbb = NULL; aaa = func1(); bbb = func2(); } const char* func1() { const char* str = NULL; str = "test"; return str; } std::vector<const char*>* func2() { std::vector<const char*>* str2 = NULL; str2->push_back("test2"); str2->push_back("test3"); return str2; } 現在必要に迫られてC++勉強中です。よろしくお願いいたします。

  • stringのデータではswitch文は使えない?

    String^ id_data_str というのに、"313131313131"というデータを入れて、下のGet_idというクラスを作って、”111111”というデータをとれるようにしたいと思ったのですが、 Get_id^ Get_id; Get_id_get(id_data_str); switch文は整数型出ないとダメだというエラーが出てきたのですが、このようなクラスのプログラムはダメなんでしょうか?何か解決方法などいただけませんでしょうか? namespace HomeBank { using namespace System; using namespace System::Collections::Generic; /** * 明細データクラス */ ref class Get_id { private: public: String^ ID_str; String^ ID_str_complete; //array<String^>^ Wireless_ID_str = gcnew array<String^>(32); public: Get_id() { ID_str = "test"; ID_str_complete = "test"; } void Get_id_get(String^ ID_str) { int i; String^ test_str; String^ str_data; Get_id(); ID_str_complete = ID_str; for(i=0;i<6;i++) { test_str = ID_str->Substring( i*2, 2 ); switch(test_str) { case "30": str_data = "0"; break; case "31": str_data = "1"; break; case "32": str_data = "2"; break; case "33": str_data = "3"; break; case "34": str_data = "4"; break; case "35": str_data = "5"; break; case "36": str_data = "6"; break; case "37": str_data = "7"; break; case "38": str_data = "8"; break; case "39": str_data = "9"; break; case "61": str_data = "A"; break; case "62": str_data = "B"; break; case "63": str_data = "C"; break; case "64": str_data = "D"; break; case "65": str_data = "E"; break; case "66": str_data = "F"; break; default; str_data = "_"; break; } if(i==0) ID_str_complete = str_data; else ID_str_complete += str_data; } } }; }