TITLE: a template definition for NULL (Newsgroups: comp.std.c++, 5 Jan 97) MEYERS: Scott Meyers > A few months ago Ted Clancy proposed this for a non-int NULL: > > const class { > public: > template operator T*() const { return 0; } > private: > void operator&(); // disallow taking the address of NULL > } NULL; > > This strikes me as a promising approach: NULL is not an int, and it's > convertible to any type of pointer. Comments? [ Note that this uses a newer feature called member templates. Basically this class allows the compiler to define an operator* for each type T encountered at each usage in the code. In otherwords, its like the class whose instance is NULL has an infinitely expandable number of operator* -adc ] CLANCEY: Ted Clancy Well, I'll comment that I like the idea, (but I thought of it, so of course I like it). I'll just point out that it has the benefits of other ideas presented here, but requires no changes to the language specification, so it should be easy to add to the standard (maybe the stl) without any side effects. It is grep-able, it has no overhead (just include it in a header -- it's a const, and all functions are inline), it is not a MACRO, and I think it should solve the varargs problem (though I haven't been able to try it out because my compiler doesn't support member templates). As a further suggestion, perhaps it should be spelt "null" in lower-case, just like the other standard library elements. That way, NULL can remain a MACRO (which can be set to 0, or to the new "null"), in accordance with the current standard (which states NULL should be a MACRO), in order to please compiler vendors who don't support member templates yet. People could start using the new "null" as the old MACRO "NULL" is kept for compatibility, or phased out (as MACROs should be, some would say). As for people who don't think the null pointer is a problem worthy of debate, even Bjarne Stroustrup in the D&E says he thinks the current NULL is a problem, and it is unfortunate that C is more type-safe than C++ in this respect. He just thought that there wasn't an easy solution. (He didn't have member templates when he wrote that). And I'd like to acknowledge the contribution of someone whose name I can't remember but I have written down somewhere (Andrew something?). My original suggestion had operator& return 0. He suggested making it void and private. COMEAU: comeau@panix.com (Greg Comeau) Not any type. As mentioned, I believe this kind of thing seems to be where people need to fiddle to address this. Some thoughts follow. This class does seem to address the common two raised points: * With Comeau C++, something such as: int i = NULL; produces: error: no suitable conversion function from "NULL" to "int" exists so that's good. * It certainly does distinguish between: void foo(int); void foo(T*); without a problem. Some other things, continuing on both sides of the fence: * You still need a header file. Nothing lost, nothing gained, though you do need to know the name of this one. * As well, you probably don't want to call this NULL so it enters the pool of all the other names people have used over the years. OTOH, you will NEVER escape typing NULL no matter how hard you try. * You don't need <>'s so that's good. * W/o fiddling with the member template, this seem to be a pointer-only thing at first glance, so that's good. That is, it is ok with pointers to object and pointer to functions. * To get it ok with pointers to members perhaps you'll need a: template operator T C::*() const { return 0; } * The case of something such as: char *pc = NULL; if (NULL == pc)... is ok, though this is not: if (NULL == 0)... and so perhaps an op void *() needs to specifically specialized. * Passing NULL to a variadic function is still a problem. Is making a private NULL copy ctor enough for all cases? (IOW, simply disallow it to be passed anywhere-- this is probably consistent along the lines of void *'ness.) * You need to give the class a name, because you want diagnostics to make sense (see the diagnostic above). However, this means that now you can declare objects of NULL's. And you cannot make the ctor private because then you cannot get the NULL object itself. The same applies for making the NULL object const. * An io capability may or may not be wise to add (probably not). The pro sides of course may be fine for some. The above has no thought whatsoever into deep dark pathological cases that no doubt exist. Anybody have any? OTOH, there is probably some instrumentation goodies one can get out of this if more is added. Just to recap, it seems we are looking at something more like this: const class Null { void operator&(); Null(const Null&); public: template operator T* () const { return 0; } template operator T C::*() const { return 0; } operator void*() const { return 0; } friend ostream& operator<<(ostream& o, const Null& me) { o << (void*)me; return o; } // if at all, assume void *? void *value() const { return 0; } // of any use??? } Null;