views:

237

answers:

2

Hi,

I would like to write a wrapper class with all operators overloaded such that I can detect when we write/read or modify its contents. For instance:

probe<int> x;
x = 5;     // write
if(x) {    // read
   x += 7; // modify
}

Anyone already did that? If not which operators must I overload to be sure I dont miss anything?

+2  A: 

Use this as a common idea. There are plenty of operators like &= |= [] which maybe are not principal in your case.

template < typename T >
struct monitor
{
    monitor( const T& data ):
        data_( data )
    {
        id_ = get_next_monitor_id(); 
    }

    monitor( const monitor& m )
    {
       id_ = get_next_monitor_id();

       m.notify_read();
       notify_write();

       data_ = m.data_;
    }

    operator T()
    {
        notify_read();
        return data_;    
    }

    monitor& operator = ( const monitor& m )
    {
        m.notify_read();
        notify_write();

        data_ = m.data_;
        return *this;
    }

    monitor& operator += ( const monitor& m )
    {
        m.notify_read();
        notify_write();

        data_ += m.data_;
        return *this;
    }
/*
    operator *=
    operator /=
    operator ++ ();
    operator ++ (int);
    operator -- ();
    operator -- (int);
*/
private:
    int id_;
    T data_;

    void notify_read()
    {
        std::cout << "object " << id_ << " was read" << std::endl;
    }

    void notify_write()
    {
        std::cout << "object " << id_ << " was written" << std::endl;
    }
};
Mykola Golubyev
Why not the ++, -- as well?
dirkgently
++ and -- postfix and prefix (http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.14)
Helltone
Understood. Changed. Thanks.
Mykola Golubyev
MSalters
a simple example with std::cout << "read/write/modify" would be welcome
Helltone
Mykola Golubyev
It's not very common, but I did use it in my last project.
Adrian Grigore
@Helltone: you can put cout << "attempt to modify" to all operators, put "attempt to read" to copy constructor and operator T().
Mykola Golubyev
Note that you are limiting the usage. You cannot pass the wrapper as a non-const reference to a function taking the wrapped type. The cast operator will provide you with a temporary, but not with a reference.
David Rodríguez - dribeas
@dribeas: If a function expect an wrapped type and we pass montior there, simply will be called operator T() and read notification will take place. What is the problem, can you describe in other words?
Mykola Golubyev
+1  A: 

You can't, I think. operator?: isn't overloadable. Also, if T::T(int) is defined, T foo = 4 is legal but T foo = probe<int>(4) isn't. There's at most one user-defined conversion.

Furthermore, because probe is not a POD, the behavior of your program can change.

MSalters
T foo = probe<int>(4) is legal.
Mykola Golubyev
can you provide an example of the problem you mentionned with "?:"
Helltone
@Mykoala: T foo = T(probe<int>(4)); would be legal. probe->int->T is two conversions.A prob with ?: exists when you use probe<int> as second arg and probe<float> as the third. No common type. With operator+(probe<int>, probe<float>) you can fix it with lot of overloads.
MSalters
Can't we fix it with a base class ?
Helltone
No - int cannot be used as a base class.
MSalters