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?
-
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?
mch : Second that, why on earth!?Daniel Earwicker : One good reason would be to make the default constructor properly construct the contained type. So no more uninitialized variables.Andrew Grant : That is not a good reason IMO!Tanveer Badar : Not good enough. Compilers warn about uninitialized variables anyway.A. Levy : Maybe YOUR compiler warns about uninitialized variables. Not every compiler is necessarily setup to do so. -
I'm not sure if
boost::refis 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.
-
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 bothTtoAttribute<T>andAttribute<T>toTwhich causes problems while overloading - but you could fix that by making the constructor ofAttribute<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 createoperator+=, and it will provide youoperator+. You createoperator<andoperator==and it will give you the other relationals etc. -
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. -
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.
-
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.
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.