0

「C++ Primer」(第 4 版) の第 16.1 章を読んでいると、簡単なテンプレートのデモがあります。

// implement strcmp-like generic compare function
// returns 0 if the values are equal, 1 if v1 is larger, -1 if v1 is smaller
template <typename T>
int compare(const T &v1, const T &v2)
{
    if (v1 < v2) return -1;
    if (v2 < v1) return 1;
        return 0;
}

メイン関数での呼び出し:

int main ()
{
    // T is int;
    // compiler instantiates int compare(const int&, const int&)
    cout << compare(1, 0) << endl;
    // T is string;
    // compiler instantiates int compare(const string&, const string&)
    string s1 = "hi", s2 = "world";
    cout << compare(s1, s2) << endl;
    return 0;
}

このコードにいくつかの変更を加えました。

//----------------------------test.cpp start----------------
#include <iostream>
#include <string>

using namespace std;

template<class T>
int myCompare(const T &v1, const T &v2){
    cout << v1 << " " << ((v1 > v2) ? (">") : ((v1 < v2) ? ("<") : ("="))) << " " << v2 << endl;
    return (v1 > v2) ? (1) : ((v1 < v2) ? (-1) : 0);
};

int main(void) {
    int iRes;
    cout << "String 1 : " << "A"<<endl;
    cout << "String 2 : " << "a"<<endl;
    iRes = myCompare("A", "a");
    cout << "A " << ((iRes == 1) ? (">") : ((iRes == (-1)) ? ("<") : ("="))) << " a" << endl;
    return 0;
};
//----------------------------test.cpp end----------------

コンパイルして実行すると問題が発生します。

VS2008 では、次のようになります。

String 1 : A
String 2 : a
A > a
A > a

g++ (Debian 4.4.5-8) 4.4.5 では、次のようになります。

String 1 : A
String 2 : a
A < a
A < a

正解は**A<a**です。

ただし、次をコメントアウトすると:

cout << "String 1 : " << "A" << endl;
cout << "String 2 : " << "a" << endl;

VS2008 では、次のようになります。

String 1 : A
String 2 : a
A < a
A < a

g++ (Debian 4.4.5-8) 4.4.5 では、次のようになります。

String 1 : A
String 2 : a
A > a
A > a

コンパイルコマンドは次のとおりです。

g++ test.cpp -o test -Wall -O0

なぜこれが起こるのか知りたいですか?問題の (A?B:C) 表現は間違っていますか? 私のコードは正しいようです。それは何日も私を悩ませました。どんな助けでも大歓迎です。


ケースクローズ!

myCompare() 呼び出しを次のように置き換えました。

iRes=myCompare(static_cast<string>("A"), static_cast<string>("a"));

できます。どのように文脈を変えても、常に正しい答えが得られます。2 つを比較していることに注意する必要がありconst char*ました。確認のために試してみました。

ここで学んだ教訓は、このテンプレートを 2 つの関数にインスタンス化できるということです。

int compare(const char* &v1, const char* &v2);     // two pointers
int compare(const string &v1, const string &v2);   // two objects

皆さんが提供してくれたすべての助けに感謝します。本当に感謝!良い一日を過ごしてください!


追加情報。

myCompare 関数に単純な表現を追加しました。

cout<<"the type is : "<<typeid(T).name() <<endl;

これにより、T がインスタンス化された型の種類に関する明確な型情報が得られます。コード全体は次のとおりです。

//----------------------------test.cpp start----------------
#include <iostream>
#include <string>
#include <typeinfo>

using namespace std;

template<class T>
int myCompare(const T &v1, const T &v2){
    cout<<"the type is : "<<typeid(T).name() <<endl;
    cout<<v1<<" "<<((v1>v2)?(">"):((v1<v2)?("<"):("=")))<<" "<<v2<<endl;
    return (v1>v2)?(1):((v1<v2)?(-1):0);
};

int main(void){
    int iRes;
    iRes=myCompare(1234, 3);
    iRes=myCompare("test","poor");
    iRes=myCompare(static_cast<string>("test"),static_cast<string>("poor"));
    iRes=myCompare(21.23,4.0);
    return 0;
};

//----------------------------test.cpp end----------------

このプログラムのこの結果は次のとおりです。

the type is : i
1234 > 3
the type is : A5_c
test > poor
the type is : Ss
test > poor
the type is : d
21.23 > 4

次の点に注意してください。

1, #include <typeinfo> should be included.
2, the second comparison is incorrect, it simply compares the addresses of the constant char array rather than string stored in the constant char array.

これが、テンプレートに苦労している私のような人の助けになることを願っています。

4

2 に答える 2

2

You are currently comparing the values of the pointers, rather than considering const char * as a string, which is nearly never what you want. If you want to compare const char * as std::strings, you should specialise your template.

template<>
int myCompare(const char *const &v1, const char *const &v2){
    return myCompare<std::string>(v1, v2);
};

Or perhaps, call strcmp in that case,

template<>
int myCompare(const char *const &v1, const char *const &v2){
    return strcmp(v1, v2);
};
于 2013-02-19T17:24:30.183 に答える
1

The difference between your code and the original is the type deduced as T. In the original, they're passing std::string objects into compare(). You're passing character literals, which are of type const char[], which decays into const char* on template argument deduction.

In other words, your function ends up comparing the literals' addresses, not their contents.

于 2013-02-19T17:25:24.983 に答える