Re: generic NULL / INVALID extension for class
Here's the result, which "works for me":
-------------------------------------
#ifndef VALUEEXTENSION_H_
#define VALUEEXTENSION_H_
/**
* This module supports adding value conditions like
* "unknown", "null", "none", "invalid", etc to class X.
* Purpose is to ease handling such conditions for X object factories
and their users
* - with minimum impact to the classes X themselves.
* The only requirements for class X are:
* 1) it has to public inherit from the related base class(es) of this
module
* to add the new value condition
* 2) it has to provide some static mkDummy() factory for dummy
objects,
* which this module can model to X::Unknown(), X::Invalid(),
X::Null(), etc images.
* The mkDummy() result does NOT necessarily need to be a complete
instance of X.
* I.e. efforts for its construction can be minimized.
* But it MUST support compliant operator==/operator!= for X.
*
* Notes
* Only mutual excluding additional values conditions are
supported.
* but NOT combinatory value conditions.
*
* TODO:
* I yet didn't find a way to drop the requirement for a mkDummy()
method for X.
* The problem is, that e.g. _None<X> needs to be compatible with
type X
* - i.e. it needs to be an instance of X (properly "flavoured").
* But _None<> doesn't "know" about which c'tor are provided by X
* and which parameters they require.
* The only other option, that came up my mind was to require a
DEFAULT c'tor for X always.
* But this could also have side-effects for X API and its users.
* A solution might be to use some existing default c'tor - if it
is already available.
* And require X to add some private default c'tor for _None<X> (as
friend)
* - in case there is yet not default c'tor.
* This is still under investigation.
*/
#if 0 // DISABLED for "comment code"
/**
* example, but a macro (see below) is used to support arbitrary value
extension
*/
template <class C>
class _None
{
private:
bool _isNone;
public:
_None() : _isNone(false) { /* void */ }
~_None() { /* void */ }
bool isNone() const { return _isNone; }
bool operator==(_None const& rhs)
{
return _isNone == rhs._isNone;
}
bool operator!=(_None const& rhs)
{
return !operator==(rhs);
}
static C& None()
{
static C dummy = C::mkDummy();
static bool prime_time(true);
if (prime_time) {
prime_time = false;
dummy._isNone = true;
}
return dummy;
}
};
/**
* user class sample
*/
class X : public _None<X>
{
private:
int _a;
public:
X(int a) : _a(a) { /* void */ }
~X() { /* void */ }
static X mkDummy() { return X(4711); } // required for _None<>
et.al. !!!
int operator() () { return _a;}
bool operator==(X const& rhs)
{
// base class evaluation required !!!
if (_None<X>::operator!=(rhs)) {
return false;
}
// own stuff evaluation
if (_a != rhs._a) {
return false;
}
return true;
}
bool operator!=(X const& rhs)
{
return !operator==(rhs);
}
};
#endif // DISABLED for "comment code"
#define _CREATE_VALUE_EXTENDING_BASE_CLASS(STATE_NAME) \
template <class X> \
class _##STATE_NAME \
{ \
private: \
bool _is##STATE_NAME; \
public: \
_##STATE_NAME() : _is##STATE_NAME(false) { /* void */ } \
~_##STATE_NAME() { /* void */ } \
bool is##STATE_NAME() const { return _is##STATE_NAME; } \
\
bool operator==(_##STATE_NAME const& rhs) \
{ \
return _is##STATE_NAME == rhs._is##STATE_NAME; \
} \
\
bool operator!=(_##STATE_NAME const& rhs) \
{ \
return !operator==(rhs); \
} \
\
static X& STATE_NAME () \
{ \
static X dummy = X::mkDummy(); \
static bool prime_time(true); \
if (prime_time) { \
prime_time = false; \
dummy._is##STATE_NAME = true; \
} \
return dummy; \
} \
};
/**
* some "standard" extensions
*/
_CREATE_VALUE_EXTENDING_BASE_CLASS(None)
_CREATE_VALUE_EXTENDING_BASE_CLASS(Invalid)
_CREATE_VALUE_EXTENDING_BASE_CLASS(Null)
-------------------------------------------
and here a little test program
-----------------------------------
#include <iostream>
using namespace std;
#include "value_extension.h"
class X : public _None<X>
{
private:
int _a;
public:
X(int a) : _a(a) { /* void */ }
~X() { /* void */ }
static X mkDummy() { return X(4711); } // required for None<> et.al.
int operator() () { return _a;}
bool operator==(X const& rhs)
{
// base class evaluation
if (_None<X>::operator!=(rhs)) {
return false;
}
// own stuff evaluation
if (_a != rhs._a) {
return false;
}
return true;
}
bool operator!=(X const& rhs)
{
return !operator==(rhs);
}
};
X func1()
{
return X(4711);
}
X func2()
{
return X::None();
}
int main()
{
X a(10);
X b(5);
cout << "a holds '" << a() << "'" << endl;
cout << "b holds '" << b() << "'" << endl;
cout << endl;
cout << "b.isNone is '" << b.isNone() << "'" << endl;
cout << "X::None().isNone() is '" << X::None().isNone() << "'" <<
endl;
X get1 = func1();
cout << "get1.isNone() is '" << get1.isNone() << "'" << endl;
X get2 = func2();
cout << "get2.isNone() is '" << get2.isNone() << "'" << endl;
if (func1() == X::None()) {
cout << "func1() returns X::None()" << endl;
}
else {
cout << "func1() returns NOT X::None()" << endl;
}
if (func2() == X::None()) {
cout << "func2() returns X::None()" << endl;
}
else {
cout << "func2() returns NOT X::None()" << endl;
}
if (func2() != X::None()) {
cout << "func2() returns != X::None()" << endl;
}
else {
cout << "func2() returns NOT != X::None()" << endl;
}
return 0;
}
--------------------------------
I would like to get rid off using macro here.
And the flaw listed as TODO.
But yet don't know how(?)
rgds
Frank