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

このQ&Aのポイント
  • C++の関数テンプレートで特殊化のエラーが発生しています。
  • 特殊化の部分に誤りがある可能性があります。
  • 特殊化の引数の型が合っていない可能性があります。
回答を見る
  • ベストアンサー

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 []' に変換できません。 とでてしまいます。 色々探してみたのですが、解決できませんでした・・。 特に最初のほうのエラーがよくわかりません。ちゃんと特殊化してる気はするのですが・・。 間違っている箇所の正当を載せていただけるとわかりやすくて、ありがたいです。 よろしくお願いします!

  • jaron
  • お礼率80% (28/35)

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

  • ベストアンサー
  • vaguechat
  • ベストアンサー率85% (47/55)
回答No.4

> template <class Type> Type minof(const Type x[], int n) という形で作ることと、 > const  char *型に明示的に特殊化したもの を作ることという要求に近いものとしては、 #include <iostream> template <typename 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* const x[], 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]; for(int i = 0; i < n; i++){ std::cout << i + 1 << "番目---"; std::cin >> a[i]; } std::cout << "文字列\n"; for(int i = 0; i < n; i++){ std::cout << i + 1 << "番目---"; s[i]=new char[64]; std::cin >> s[i]; } std::cout << "整数の最小値---" << minof(a, n) << "です\n"; std::cout << "文字列の最小値---" << minof<const char *>(s, n) << "です\n"; } とか? > char s[n][64]; はテンプレートに合わせるためにchar*の配列に修正している。 各char*の領域はプログラムはすぐ終わるしnewしてdeleteはしてない。 あと、比較の不等号の向きは逆だと思うので反転している。 x[min]よりx[i]が小さいときに最小値を更新するのだと思う。

その他の回答 (4)

  • vaguechat
  • ベストアンサー率85% (47/55)
回答No.5

ごめん、補足。 #include <cstring> の抜けと for(int i = 1; i < n; i++) if(std::strcmp(x[min], x[i]) > 0) min = i; にしないと。 g++では特に何もしなくてもコンパイルできてしまったのでつい。

jaron
質問者

お礼

おぉ・・strcmp関数は文字列の先頭のアドレスさえ渡せばいいから、わざわざ多次元配列で作らなくて、new演算子で先頭のアドレスだけ入手すればよかったんですね・・! まさかこんなところでもnew演算子が役に立つとは思いもしませんでした。 あと、プログラム自体の間違いも指摘していただいて・・ ありがとうございました!

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.3

間違ってたので修正のうえ再貼り付け。 #include <iostream> #include <string.h> using namespace std; template <class Type> int less_than( Type x, Type y ){ cout << "DEBUG(G):" << x << "," << y << "=" << (x<y) << endl; return x < y; } int less_than( const char *x, const char *y ){ cout << "DEBUG(c*):" << x << "," << y << "=" << strcmp(x,y) << endl; return strcmp( x, y ) < 0; } template <class Type> Type minof( const Type x[], const int n ){ int min = 0; for( int i = 1; i < n; i++ ) if( less_than( x[i], x[min] ) ) min = i; return x[min]; } int main( int argc, char *argv[] ){ const char *a[] = { "test1", "test2", "t3", "test 4", "test No.5" }; cout << "Min of a:" << minof( a, sizeof a/ sizeof *a ) << endl; const int b[] = { 3,4,2,1,5 }; cout << "Min of b:" << minof( b, sizeof b/ sizeof *b ) << endl; }

jaron
質問者

お礼

おぉ~、テンプレート関数の中にテンプレート関数を用いて、ムリに一つのテンプレート関数で実現しようとせずにしているわけですか! この発想はありませんでした・・。 確かにこの方がテンプレート関数の引数が書きやすくていいですね! なれない多次元配列の受け渡しなどをしてないから分かりやすいです ありがとうございました

回答No.2

特殊化というのは<class TYPE>のTYPEの部分がある型のときに処理を変えたいということなので、 template<class Type> Type minof(const Type x[], const int n) の TYPE部分をconst char*に変えても template<> const char* minof<const char *>(const char x[][64], const int n) にはならない。つまり、 template<> const char* minof<const char *>(const char x[][64], const int n) の一般系(特殊型以外)の定義がないからエラーになるのだと思います。 例えば、 template<class Type> Type minof(Type x[], const int n) template<> char* minof<char*>(char* x[], const int n) ならエラーにならないはずです。 (ただし、上記の例をもちいるなら、関数本体も変えなければなりませんが・・・・・・)

jaron
質問者

お礼

なるほど、特殊化にはそのような原理?みたいなものがあるんですね! ただ単に上のテンプレート関数と同じ名前をしていたら、あとは引数の型とかは自由だと思ってました・・・。 分かりやすく教えてくださってありがとうございました!

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

一例 #include <iostream> #include <string.h> using namespace std; template <class Type> int less_than( Type x, Type y ){ return x < y; } int less_than( const char *x, const char *y ){ cout << "DEBUG:" << x << "," << y << "=" << strcmp(x,y) << endl; return strcmp( x, y ) > 0; } template <class Type> Type minof( const Type x[], const int n ){ int min = 0; for( int i = 1; i < n; i++ ) if( less_than( x[min], x[i] ) ) min = i; return x[min]; } int main( int argc, char *argv[] ){ const char *a[] = { "test1", "test2", "t3", "test 4", "test No.5" }; int n = sizeof a / sizeof *a; cout << "Min of a:" << minof( a, n ) << endl; }

関連するQ&A

  • c++について

    入力した値が123または456で一致したら一致と表示したいのですがどうfor文を回すか分かりません。 ご助力願います_(._.)_ class N { bool hit(const char* a[],const char* b) {   for(int i=0;i<*a[i];i++) if(*a[i]!=b[i]) { return false; } return true ; } public: N() { const char* a[ ]={ "123","456"}; char b[4]; int num; cin>>num; sprintf_s(b, 4, "%03d", num); if(hit(a,b)) cout<<"一致"; else cout<<"不一致"; } };

  • c++11での文字列リテラルの特殊化について

    c++11言語でのテンプレート部分特殊化についての質問です。 コメントアウト部分は出力結果です template<class T> struct VT { static const int type = 1;}; template<class T,int N> struct VT< T[N] > { static const int type = 2;}; template<class T,int N> struct VT< const T[N] > { static const int type = 3;}; template<class T> struct VT< T* > { static const int type = 4;}; template<class T> struct VT< const T*const > { static const int type = 5;}; #include<iostream> #include<typeinfo> int main(){ std::cout<<"A:"<< VT< char >::type << std::endl; // A:1 std::cout<<"B:"<< VT< char[10] >::type << std::endl; // B:2 std::cout<<"C:"<< VT< char* >::type << std::endl; // C:4 std::cout<<"D:"<< VT< char const [1] >::type << std::endl; // D:3 std::cout<<"E:"<< VT< decltype("") >::type << std::endl; // E:1 std::cout<<"G:"<< typeid( char const [1] ).name() << std::endl;// G:char const [1] std::cout<<"H:"<< typeid( "" ).name() << std::endl;// H:char const [1] } 型名を直接記述したD,G、文字列リテラルを記述したE,H。 コンパイラ毎の差はあれど、GとHの型名は同じものが表示されます。 ですが、[D:3] [E:1]と値は違い、別の特殊化テンプレートが使われています。 この部分が分かりません。 また、配列リテラル、文字列リテラルに対し部分特殊化テンプレートを宣言する方法などありましたら、ご教示お願いします。

  • C言語の穴埋め問題です

    次のプログラムは、初期化により文字列を定義し、辞書式配列にしたとき、どの文字列が先頭にくるかを調べるプログラムなのですが。■■■を教えてください #include <stdio.h> #include <string.h> #define N 5 //関数のプロトタイプ宣言 char *min(char *p[] , int n); int main(void) { char *p[N] = {"Hello" , "Hi" , "Happy" , "HaHaHa" , "Heaven"}; printf("辞書式配列で先頭となる文字列は%s\n" , ■■■); } char *min(char *p[] , int n) { int min; //最小値のアドレス Int i; //カウンタ min = 0; for(i = 1; i < n; i++){ if (strcmp(■■■ , ■■■) > 0){ ■■■= ■■■; } } return ■■■; }

  • C言語の穴埋め問題です

    配列に初期化されたデータの中から最小値を求めるプログラムなのですが、■■■を教えて頂けないでしょうか? #include <stdio.h> #define N 5 //関数のプロトタイプ宣言 int min(int *p , int n); int main(void) { int data[N] = {15,34,28,12,33}; printf("最小値は%d\n" , ■■■); } int min(int *p , int n) { int min; //最小値 int i; //カウンタ min = *p; for(i = 1 , ■■■; i < n; i++ , ■■■){ if (min >■■■ ){ min =■■■ ; } } return ■■■; }

  • C++で分からないプログラムがあるんですが

    #include <iostream> #include <cmath> using namespace std; int main() { static const int N = 2; double va[N]={3,-4}; double vb[N]={4,3}; double a,b; double p; for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) { } } cout << "va + vb = (" ; for (int i = 0; i < N; ++i) { cout << va[i] + vb[i]; if (i < N - 1) { cout << ", "; } } cout << ")" << '\n'; cout << "va - vb = (" ; for (int i = 0; i < N; ++i) { cout << va[i] - vb[i]; if (i < N - 1) { cout << ", "; } } cout << ")" << '\n'; p = 0; for (int i = 0; i < N; ++i) { p += va[i] * vb[i]; } cout << "va・vb = " << p << '\n'; a = 0; for (int i = 0; i < N; ++i) { a += va[i] * va[i]; } a = sqrt(a); b = 0; for (int i = 0; i < N; ++i) { b += vb[i] * vb[i]; } b = sqrt(b); if (a * b != 0) { cout << "cosθ = " << p / (a * b) << '\n'; } return 0; } これで、ベクトルの加減とベクトルの内積とcosθが出るんですが、2つのベクトルを適当に初期化しないといけないんですが、初期化ってこれで初期化ってできてますか?

  • C言語でわからない問題があります

    下のプログラムのXXXの値なのですが、何を返すのかがわかりません プログラム(1)と(2)では、処理にどういう違いがあるのでしょうか、できれば教えてください プログラム(1) #include <stdio.h> #define N 5 //関数のプロトタイプ宣言 int min(int *p , int n); int main(void){ int data[N] = {15,34,28,12,33}; int index; //最小値の位置 index = min(data,N); printf("最小値はdata[%d]で%d\n" , index, data[index]); } int min(int *p , int n){ int *pmin; //最小値のアドレス int i; //カウンタ pmin = p; for(i = 1; i < n; i++){ if (*pmin > *(p+i)){ pmin = p+i; } } return XXX; } プログラム(2) #include <stdio.h> #define N 5 //関数のプロトタイプ宣言 int *min(int *p , int n); int main(void){ int data[N] = {15,34,28,12,33}; int *p; //最小値の位置 p = min(data,N); printf("最小値は%d\n" , *p); } int *min(int *p , int n){ int *pmin; //最小値のアドレス int i; //カウンタ pmin = p; for(i = 1; i < n; i++){ if (*pmin > *(p+i)){ pimn = p+i; } } return pmin; }

  • C++の問題で困っています。

    C++の問題で困っています。 今,C++の入門書を読んでその中の演習問題に取り組んでいるのですが、この本には答えがついていないみたいなので、問題で悩んでいます。 お力を貸してください。 問題 「文字列 s に含まれる最も先頭に位置する文字 c へのポインタを返す関数 strchr_ptr を作成せよ。型は char * strchr_ptr(const char *s, char c); とする。例えば、文字列 s が "ABSZXYX" で文字 c が 'X' であれば、返却するのは &s[4]である。 なお、文字 c が文字列 s に含まれない場合は NULL を返却すること。 」 です。 僕はこの問題に対して、以下のように答えました。 ヘッダのインクルードなどは省きます。 char *strchr_ptr(const char *s, char c) {         for(int i = 0; s[i]; i++)         if(s[i] == c)             return const_cast<char *>(&s[i]);     return NULL; } int main() {     char s[36] = "ABSZXYX";     cout << strchr_ptr(s, 'X') << "\n";     cout << &s + 4 << "\n"; } と書きました。 cout << &s + 4 << "\n"; はこの上の文で導き出したアドレスがあっているか確かめるものです。 ですが、これをコンパイルして実行すると、 ----------------- XYX 0012FFE0 ----------------- となり、関数側のほうはアドレス的な表記をしてくれません・・。 どうにかして、アドレス表記にしようとあれこれ考えたのですが、どうしても出来ませんでした。 どのようにしたらいいのか教えてください。 初歩的な質問ですが、よろしくお願いします。

  • C言語/プログラミング

    int Sutar(int i, int j) { for (i = 1; i <= 5; i++) { for (j = 0; j < i; j++) { cout << "★¥n"; } cout << "¥n"; } return i, j; } int main() { int i; cout << "★を何個出力しますか?¥n"; cin >> i; cout << "★を" << Sutar(i, j) << "個出力に成功しました。¥n"; return 0; } これで、実行したらエラー発生しました。エラーを治す方法を教えてください。

  • この問題を教えてください

    配列に初期化されたデータの最小値を求めるプログラムなのですが この問題のX,Yの部分がわかりません 教えて頂けないでしょうか? #include <stdio.h> #define N 5 //関数のプロトタイプ宣言 int min(int *p , int n); int main(void) { int data[N] = {15,34,28,12,33}; printf("最小値は%d\n" ,X); } int min(int *p , int n) { int min; //最小値 int i; //カウンタ min = *p; for(i = 1; i < n; i++){ if (min >Y ){ min = Y; } } return min; }

  • C++ ソートのやり方

    僕が作ったプログラムで、これはバブルソートなのかわからないので教えてください。 また、ほかのソートの仕方も教えてください。 よろしくお願いします。 汎用関数を使っているのでわかりにくいかもしれないですがお願いします。 #include <iostream> using namespace std; template <class X>void Sort(X *data, int size) { X temp; for (int i = 0; i < size; i++){ for (int j = i + 1; j < size; j++){ if (data[i]>data[j]){ temp = data[i]; data[i] = data[j]; data[j] = temp; } } } } int main() { int i[10]{1, 4, 3, 5, 2, 10, 2, 7, 6, 8}; char c[10]{'c', 'b', 'z', 'a', 'x', 'y', 'j', 'n', 'm', 'r'}; Sort(c, 10); Sort(i, 10); for (int j = 0; j < 10; j++){ cout << i[j] << ' '; } cout << endl; for (int j = 0; j < 10; j++){ cout << c[j] << ' '; } cout << endl; getchar(); return 0; }