How to distinguish read/write operations when using operator[]
<p>I'd need to write a class with an overloaded operator [] which has different behavior when the operator [] is used to read or write data.
To give a practical example of what I want to achieve, let's say I have to write the implementation of a class named PhoneBook which can be used in the following way:</p>

<pre><code>PhoneBook phoneBook(999999); // 999999 is the default number which should be
                             // used when calling someone who is not in the phone book

phoneBook["Paul"] = 234657;  // adds Paul's number
phoneBook["John"] = 340156;  // adds John's number

// next line should print Paul's number 234657
cout &lt;&lt; "To call Paul dial " &lt;&lt; phoneBook["Paul"] &lt;&lt; endl;
// next line should print John's number 340156
cout &lt;&lt; "To call John dial " &lt;&lt; phoneBook["John"] &lt;&lt; endl;
// next line should print 999999 because Frank is not in the phone book
cout &lt;&lt; "To call Frank dial " &lt;&lt; phoneBook["Frank"] &lt;&lt; endl;
</code></pre>

<p>The problem is in the fact that when using</p>

<pre><code>phoneBook["Frank"]
</code></pre>

<p>I don't want to add an entry in the phone book for Frank, otherwise a solution based on std::map would be easy to implement.</p>

<p>I did not find on the web any standard way to achieve this so 
after some thinking I came up with the following solution in which the operator [] returns a "temporary object" named PhoneNumber. PhoneNumber is then used to distinguish between read/write operations:</p>

<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;map&gt;

using namespace std;

class PhoneBook{
private:
    map&lt;string, int&gt; data_; // stores phone numbers
    int defaultNumber_; // default number returned when no matching name is found

public:
    PhoneBook(int defaultNumber) :
        defaultNumber_(defaultNumber) {}

    // Searches in the phone book for a name. If the name is found it returns
    // the corresponding number. If the name is not found it returns defaultNumber_
    int read(string name){
        map&lt;string, int&gt;::iterator it = data_.find(name);
        if (it==data_.end()){
            return defaultNumber_;
        } else {
            return it-&gt;second;
        }
    }

    // Forwarding function to map operator []. It is not really necessary but it is added for clarity
    int&amp; write(string name){
        return data_[name];
    }

    // Forward declaration of the "temporary object" returned by operator []
    // See declaration below
    class PhoneNumber;

    PhoneNumber operator[](string name){
        return PhoneNumber(this, name);
    }

    class PhoneNumber{
        friend class PhoneBook;
    private:
        PhoneBook* const phoneBook_;
        string name_;

        // Constructors are private so that PhoneNumber can be used only by PhoneBook
        // Default constructor should not be used
        PhoneNumber() :
            phoneBook_(NULL) {}

        PhoneNumber(PhoneBook* phoneBook, string name) :
            phoneBook_(phoneBook), name_(name) {}

    public:
        // conversion to int for read operations
        operator int (){
            return phoneBook_-&gt;read(name_);
            }

        // assignment operator for write operations
        const int&amp; operator = (const int&amp; val){
            return phoneBook_-&gt;write(name_) = val;
        }
    };
};

int main(){
    PhoneBook phoneBook(999999);

    phoneBook["Paul"] = 234657;
    phoneBook["John"] = 340156;

    cout &lt;&lt; "To call Paul dial " &lt;&lt; phoneBook["Paul"] &lt;&lt; endl;
    cout &lt;&lt; "To call John dial " &lt;&lt; phoneBook["John"] &lt;&lt; endl;
    cout &lt;&lt; "To call Frank dial " &lt;&lt; phoneBook["Frank"] &lt;&lt; endl;

    return 0;
}
</code></pre>

<p>The class PhoneBook behaves like I would like and the program prints: </p>

<pre><code>To call Paul dial 234657
To call John dial 340156
To call Frank dial 999999
</code></pre>

<p>I would like to ask you some questions:</p>

<ol>
<li>Is there any better way to obtain a class behaving like the class I coded?</li>
<li>Has the technique I'm using a name so that I can search more info about it?</li>
<li>Do you see any drawback/possible improvement in my solution?</li>
</ol>

<p>In the library I'm writing, enabling the behavior I obtained for PhoneBook::operator[]
in a similar situation is really important and I would really like to know what you think about my problem.</p>

<p>Thanks!</p>
