Re: null assignment in a template
Steve Wolf wrote:
Please excuse me if there is a better place for this post. I could
not find one in MS's communities. My question is about template
programming in C++, not really about STL.
// Initialised supplies an initial value in the variable declaration itself
// NOTE: for non-scalar types (such as floating point types) this
template won't compile
// due to the fact that it is illegal to declare a template with a
non-scalar value
// Use Uninitialised instead, and declare the value in its explicit ctor
template <typename T, T * zero>
struct Initialised<T*, zero>
{
Initialised() : m_value(zero) { }
template <typename U> Initialised(const U* that) : m_value(that) { }
template <typename U> T* & operator = (const U* that) { if (m_value
!= that) m_value = that; return *this; }
That conditional check is redundant.
int i = 5;
i = i; //perfectly ok.
T* & operator = (const int constant) { return m_value = constant; }
operator T* & () { return m_value; }
operator const T* & () const { return m_value; }
T * m_value; // the plain old data
};
What I really want is to allow myself to declare a plain old pointer and
guarantee that its initialized in the constructor or point of
declaration, to make it much easier to avoid uninitialized variables issues.
The above appears to do exactly that.
The only fly in the ointment is that the following fails:
Initialised<Widget*, new Widget(1,2,3)> m_pWidget;
That isn't going to compile, since the second arg must be an extern
pointer value, or NULL. Did you mean:
Initialised<Widget*, NULL> m_pWidget(new Widget(1,2,3));
?
...blah - blah
...some code...
...later
m_pWidget = NULL;
Since this line evaluates to Initialised::operator = (int) { m_value =
int; }
There is no conversion from int to Widget*!
Right.
Now, I can certainly do the obnoxious thing and cast int to Widget* in
operator=(int), and then leave it up to the user to ensure that any int
assignments are always the value NULL, but that's just sloppy and asking
for trouble.
Why not just assign to 'zero' inside the member, since this assignment
operator is for re-zeroing only, presumably?
What I Really Want(tm) is to be able to have m_pWidget = NULL evaluate
to a valid expression, and m_pWidget =
<any-other-integer-or-other-non-convertible-type> to error with "no
conversion from <type> to Widget*".
I keep thinking that if I can make the operator = (x) partially
specialized for operator = (NULL) I would be golden! However,
everything I've tried leads to a compiler error. I need a type for NULL
which is different from not-null and for the compiler to identify that
such that the function called in m_pWidget = NULL is one function (that
is legal), and m_pWidget = 5 results in an illegal assignment.
Any ideas / feedback would be *hugely* appreciated.
How about dropping the const int operator, and adding this:
private:
struct Dummy {};
public:
T* & operator= (int Dummy::*) { return m_value = zero; }
template <typename U>
It's impossible to pass anything to that function other than NULL, since
user code cannot form any other pointer-to-member of Dummy, since Dummy
is private.
Tom