2016-12-02 7 views
5

C++で暗黙的な変換が使用される条件を理解するのに問題があります。私がクラスを持っているとします:標準オペレータへのオペランドのC++暗黙的な変換

class SomeClass 
{ 
private: 
    int val; 
public: 
    SomeClass(int i) :val{ i } {} 
    operator string() { return to_string(val); } 
}; 

私は文字列にキャストする必要があるのはなぜですか?なぜ変換を暗黙的に実行しないのですか?

コード:ちょうどキャストを使用したとして

int main(void) 
{ 
    SomeClass sc = 4; 
    cout << (string)sc << endl; //prints 4, compiles fine 
    cout << sc << endl;//does not compile, no operator "<<" matches these operands 

    string str1 = sc;//compiles fine, performs cast 
    string str2 = "Base String" + sc;//does not compile, no operator "+" matches these operands 
} 

この質問は実用よりも学術的であるが、とにかく、より読みやすいです。

答えて

2

あなたがcout << (string)scを記述する際に使用されますoperator<< overloadが関数テンプレートである:

template <class CharT, class Traits, class Allocator> 
std::basic_ostream<CharT, Traits>& 
    operator<<(std::basic_ostream<CharT, Traits>& os, 
       const std::basic_string<CharT, Traits, Allocator>& str); 

std::stringはクラステンプレートそのものであり、かつchar以外の型でインスタンス化することができ、これはあります文字が同じ文字型のストリームに書き込まれている場合でも、印刷可能でなければなりません。実際、std::wstringではまさにそのようなことが起こります。CharTcharではなくwchar_tです。同じoperator<<が動作します(適切なストリームを使用する場合)。

cout << scと書くと、その特定のオーバーロードが考慮されます。このオーバーロードは、コンパイラがCharTと他のものに使用する型を推定できないため、拒否されます。変換が実行されていることが既に分かっている場合にのみ型を推定できますが、変換はまだ考慮されていないため、若干後の段階でのみチェックされます。

operator<<オーバーロードがあり、std::stringを要した場合は、scが暗黙的に変換されます。

+0

それで、C++の標準ライブラリ関数(キャストなし)との互換性を高めるために、stringではなく 'basic_string'への暗黙の変換を記述する必要がありますか? –

+0

@ApoorvaKharcheいいえ、 'string'は' basic_string'の特定のインスタンス化のtypedefです。 'operator <<がbasic_string で書かれているのか' string'で書かれているのかは、まったく同じことを意味するので違いはありません。 'operator'が' basic_string 'や' basic_string 'のように' T 'を推論するかどうかは違いがあり、あなた自身のクラスからはそれを制御できません。 – hvd

2

std::coutstd::stringを受け付けません。
テンプレート化されたstd::basic_stringを受け入れ、そのパラメータは推定されます。
詳細はhereを参照してください。

のは、次の例を考えてみましょう:

#include<string> 

struct SomeClass { 
    operator std::string() { return ""; } 
}; 

template <class CharT, class Traits, class Allocator> 
void f(const std::basic_string<CharT, Traits, Allocator> &) {} 

template <class CharT, class Traits, class Allocator> 
void f(std::basic_string<CharT, Traits, Allocator> &) {} 

int main(void) { 
    SomeClass sc{}; 
    f((std::string)sc); 
    //f(sc); 
} 

それはあなたのケースで何が起こるかに似ています。
もちろん、f(sc)はほとんど同じ理由でコンパイルされません。

問題は、テンプレートパラメータSomeClassを推測するとstd::stringに変換する必要があります。 std::stringに変換するには、コンパイラは有効なオーバーロードが存在すると推測し、それを使用しようとします。とにかく、このような実行可能な関数は、その観点からは存在しません。テンプレートパラメータは引き続き推測され、キャスト後にSomeClassのオーバーロードが存在すると推測する必要があります。なぜなら、そうすることはできないからです。

私はそれをチェックしていませんが、同様のことがoperator+にも当てはまると思います。

+0

downvoteには何がありますか? – skypjack

+0

それでは、C++の標準ライブラリ関数(キャストなし)との互換性を高めるために、stringではなく 'basic_string'への暗黙の変換を記述する必要がありますか? –

+0

この回答のまもなく、編集履歴は基本的に私のコピーしたように見えましたが、編集履歴は誤解を招いていました。あなたは間違った答えを投稿し、それを認識したときにそれを削除し、それを修正した。結局、私たちは基本的に同じ答えを同時に掲載しました。これが誰かがそれを下落させた理由であるならば、その人にダウンボートを元に戻してください。 – hvd

関連する問題