4

学習演習として、C++で自動型変換がどのように機能するかを調べてきました。自動型変換は一般的に避けるべきだと知っていますが、とにかくそれがどのように機能するかを理解することによって、C++の知識を増やしたいと思います。

StdStringConverter自動的にに変換できるクラスを作成しましたstd::stringが、オブジェクトを実際のオブジェクトと比較すると、コンパイラ(Debianではg ++ 4.3.4)は変換を行わないようですstd::string(参照渡しの欠如を無視してください。一時オブジェクトの不要な作成):

#include <string>

class StdStringConverter
{
public:
    explicit StdStringConverter(std::string name) : m_name(name) {}
    operator const std::string () const { return m_name; }
private:
    std::string m_name;
};

int main()
{
    StdStringConverter converter(std::string("Me"));
    const std::string name = "Me";
    // Next line causes compiler error:
    // no match for 'operator==' in 'converter == name'
    return (converter == name) ? 0 : 1;
}

一方、CStringConverterクラスに少し変更すると、自動変換行われますが、charポインターの比較はおそらく私が意図したものではありません。

#include <string>

class CStringConverter
{
public:
    explicit CStringConverter(std::string name) : m_name(name) {}
    operator const char* () const { return m_name.c_str(); }
private:
    std::string m_name;
};

int main()
{
    CStringConverter converter(std::string("Me"));
    const char* name = "Me";
    // Next line compiles fine, but they are not equal because the
    // pointers don't match.
    return (converter == name) ? 0 : 1;
}

このコンテキストでのastd::stringとaの違いについて、コンパイラがそれらを同じように扱わないようにする特別な何かがありますか?char*

4

3 に答える 3

7

この問題は、std::stringが実際にはクラステンプレートstd::basic_stringのインスタンスであるという事実が原因です。名前空間stdで使用可能なoperator==は、2つのstd::basic_stringテンプレートを使用します。


template<class charT, class traits, class Allocator>
bool operator==(const basic_string& lhs,
                const basic_string& rhs);

このバージョンのoperator==が特にstd::stringでオーバーロードされている場合、コードは問題ありません。ただし、そうではありません。コンパイラは、std :: basic_stringのテンプレートパラメータに対してテンプレート引数の推定を実行する必要があるため、変換演算子の戻りが一致する可能性があることを理解できます。

ただし、コンパイラはそれを行いません。規格のどの部分がこれを正確に述べているのかわかりません。しかし、一般的な考え方は、そのような変換は非テンプレートタイプに対してのみ機能するというものです。

私が提案できることの1つは、StdStringConverterを名前空間に配置し、その名前空間のstd::stringにoperator==のバージョンを提供することです。このように、コンパイラがそのような式を見つけると、ADL(Argument Dependent Lookup)が機能し、すべてが正常に機能します。


#include <string>

namespace n1 {

class StdStringConverter
{
public:
    explicit StdStringConverter(std::string name) : m_name(name) {}
    operator std::string () { return m_name; }
private:
    std::string m_name;
};

bool operator==(std::string const& a, std::string const& b)
{
  return a == b; //EDIT: See Paul's comment on std::operator== here.
}

}

int main()
{
    using namespace n1;
    StdStringConverter converter(std::string("Me"));
    std::string name = "Me";
    return (converter == name) ? 0 : 1;   
}
于 2009-09-18T12:36:36.540 に答える
1

最初の例では、比較された2つのクラス(stringとStdStringConverter)は、型変換のためにコンパイラーから特別な処理を受けません。つまり、作成した演算子のオーバーロードはトリガーされません。コンパイラはoperator==オーバーロードのリストを調べますが、いずれもStdStringConverterを取り込んでいないため、怒鳴ります。

2番目の例では、名前はchar*です。これはプリミティブ型であるため、コンパイラは非プリミティブをchar*に変換しようとします。オーバーライドが設定されているため、オーバーライドが機能し、アドレスを比較します。

コンパイラーは、プリミティブ型を含まない操作で型キャストを明示しません。コンストラクターを使用して型を一致させようとします。たとえば、最初の例を次のように変更した場合:

#include <string>

class StdStringConverter
{
public:
    StdStringConverter(std::string name) : m_name(name) {}
    bool operator==(const StdStringConverter &name) { return m_name == name.m_name; }
    operator const std::string () const { return m_name; }
private:
    std::string m_name;
};

int main()
{
    StdStringConverter converter(std::string("Me"));
    const std::string name = "Me";
    // Next line causes compiler error:
    // no match for 'operator==' in 'converter == name'
    return (converter == name) ? 0 : 1;
}

これで、プログラムは0を返します。コンストラクターが明示的ではないため、コンパイラーはそれを使用して文字列をStdStringConverterに変換しようとします。StdStringConverterにoperator==があるので、すべてが機能します。

于 2009-09-18T11:59:33.453 に答える
-1

複数の要因があります。このようにreturnステートメントを変更した場合

return(std :: operator ==(name、name))?0:1;

明らかに同じことはしませんが、コンパイルします。一方で

return(std :: operator ==(converter、name))?0:1;

より興味深いエラーメッセージを提供しますが、提供しません

'operator ==(StdStringConverter&、const std :: string&)を呼び出すための一致する関数がありません

これは、operator==がbasic_string<>でテンプレート化されていることを思い出させます。これには、起動する3つのテンプレートパラメーターがあります。例でstd::stringではなくintを使用する場合、コンパイラは文句を言いません。

std :: stringを使用して目的の効果を得る方法は、より興味深いものです...

于 2009-09-18T11:58:28.760 に答える