views:

444

answers:

6

I'm looking to add functionality to all the simple types in C++.

I want to write a single templated class that takes as a template parameter the type to be encapsulated and then has all the operators defined so that the encapsulated class works exactly as the simple type it encapsulates.

Something like this:

template <typename _SimpleType_>
class Attribute
{
public:
    Attribute(_SimpleType_ value){ m_value = value; }
    ~Attribute(){}

    // Cast
    operator _SimpleType_() { return(m_value); }

    // Comparisons
    bool operator==(const a& other) const { return a == m_value; }
    etc...

private:
   _SimpleType_ m_value;
}

// Use like:
Attribute<int> i = 20;

while(i)
{
   if((i & 0xF) == 0)
   {
      i >>= 2;
   }

   i--;
}  etc...

The question is I'm sure there are a load of nuances that have to be dealt with and specialised template operators written; so is there anywhere that this has already been done so that I can just use that instead?

Boost is too large and complicated to put in my project but I can look at it for pointers if there is a class like this in there - whats its name if there is?

+4  A: 

It's pretty simple, if tedious, - you just have to implement all the operators supported by the standard types and where the cast operator is not sufficient.

I have to ask though, why on earth are you trying to do this?

Andrew Grant
Second that, why on earth!?
mch
One good reason would be to make the default constructor properly construct the contained type. So no more uninitialized variables.
Daniel Earwicker
That is not a good reason IMO!
Andrew Grant
Not good enough. Compilers warn about uninitialized variables anyway.
Tanveer Badar
Maybe YOUR compiler warns about uninitialized variables. Not every compiler is necessarily setup to do so.
A. Levy
A: 

I'm not sure if boost::ref is what you're looking for.

At any rate, the best thing you'd do is to just write it out by hand -- but this will start becoming a problem if you intend to support pointer and reference semantics.

What you'd also proabably need to do is put it in a namespace and implement the free function operator overloads and rely on ADL for it to get picked up. This will get a little unwieldy though as you implement more and more operators.

Dean Michael
+2  A: 

You can get the implementation of the nonmutating operators for free, just by the conversion to _Simple_type_ (and you would get the assignments and increment/decrement by conversion to _Simple_type_&). Another question is whether this is really a good idea, as it creates conversions both T to Attribute<T> and Attribute<T> to T which causes problems while overloading - but you could fix that by making the constructor of Attribute<T> explicit.

This leaves the assignments and increment/decrement - you would just have to implement those.

Another possibility is using boost::operators - a header only library that facilitates creation of operator overloads based on algebraic rules. eg. you create operator+=, and it will provide you operator+. You create operator< and operator== and it will give you the other relationals etc.

jpalecek
+1  A: 

Not to do with your question, but you should be aware that names such as _SimpleType_ (that is, names that begin with an underscore and an uppercase character) are reserved for the C++ compiler and Standard Libarary implementors to use - you are not allowed to use them in your own code.

anon
+2  A: 

Here is an example of doing with an automatic typecast to T& (tested with GNU C++ 4.3.2):

#include <iostream>

using namespace std;

template <typename T>
class Attribute {
public:
    Attribute(const T &value) { v = value; }
    operator T & () { return v; }
private:
    T v;
};

int main(int argc, char **argv)
{
    Attribute<int> i(0);
    i = 3;
    i++;
    i += 4;
    i = i + 5;
    i <<= 3;
    cout << "i is now " << i << endl;
}

The C++ compiler casts automagically the reference to 'Attribute' to a reference to 'int' using the coercion operator 'operator T & ()'. So when the Attribute class does not provide the '++' operator or anything, the object is typecasted to int & and then the operator is looked up from there. Feel free to experiment.

antti.huima
A: 

I like this form of encapsulation of simple types (original author - Sektor van Skijlen):

template<typename T>
class explicit_t
{
private:
    T value;

    template<typename V> explicit_t(V t);
public:
    operator T&() {return value;}
    explicit_t(const T& c) : value(c) {}    
};

And the short example:

void fun(explicit_t<int> foo) {}

int main()
{
        // fun('a');
        // fun(3u);
        // fun(3.0);
        fun(4);
}

So what do I get? No more unwanted conversions.

You might also want to have a look at something more fancy - typegen.

Anonymous