
Just wondering if there was any interest in a better null, or if such a thing existed in boost already. The code is relatively simple: class null { public: explicit null ( void * ) { } ~ null ( ) { } template < typename T > operator T * ( ) { return 0; } }; null null ( 0 ); Example usage: int * p = null; // ok int i = null; // error: null cannot be converted to an int -Jason

Heh. Have you read what Scott Meyers has to say about this?
Indeed I have not. Where could I find what he has to say about this?
Item 25 of Effective C++. Definitely worth reading all three of his Effective books. Not just lots of useful advice but also a pleasure to read. Darren

Darren Cook wrote:
Heh. Have you read what Scott Meyers has to say about this?
Indeed I have not. Where could I find what he has to say about this?
Item 25 of Effective C++. Definitely worth reading all three of his Effective books. Not just lots of useful advice but also a pleasure to read.
Looks like I'll be buying them then :) In the meantime, since I'm anxious to know, may I ask whether what he had to say about such a null was positive or negative? -Jason

Jason Hise wrote:
Darren Cook wrote:
Heh. Have you read what Scott Meyers has to say about this?
Indeed I have not. Where could I find what he has to say about this?
Item 25 of Effective C++. Definitely worth reading all three of his Effective books. Not just lots of useful advice but also a pleasure to read.
Looks like I'll be buying them then :) In the meantime, since I'm anxious to know, may I ask whether what he had to say about such a null was positive or negative?
-Jason
You had: class null { public: explicit null (void *) {} ~null () {} template <typename T> operator T*() const { return 0; } }; Meyers has: const class { // This is a const object public: // convertible to any type of null non-member pointer... template <typename T> operator T*() const { return 0; } // ...or any type of null member-pointer... template <typename C, typename T> operator T C::*() const { return 0; } private: // whose address can't be taken... void operator&() const; } NULL; // and whose name is NULL. Getting there takes three pages of explanations of the pitfalls and the bottom line conclusion is that whilst this is a workable NULL, you still can't prevent your uses from writing code that results in the problems that led you to try and write this space age solution in the first place. void f(int); void f(string *); f(0); // which function is called? "As a designer of overloaded functions, then, the bottom line is that you're best off avoiding overloading on a numerical and a pointer type if you can possibly avoid it." Ie, your solution works, but its solving the wrong problem. Now go buy the book ;-) Angus

Angus Leeming wrote:
You still can't prevent your uses from writing code that results in the problems that led you to try and write this space age solution in the first place.
void f(int); void f(string *);
f(0); // which function is called?
Doesn't this call f ( int )? I was under the impression from reading a book by Sutter (I forget which) that 0 is first and foremost an int. Thus, f ( 0 ) should call the int version and f ( null ) should call the string * version. This seems very natural and reasonable to me. What is the problem here? -Jason

Jason Hise wrote:
void f(int); void f(string *); f(0); // which function is called? Doesn't this call f ( int )?
Yes.
What is the problem here?
The point of the article still holds, I think. You have your NULL class. Does it help here? Don't think so... void f(string *); void f(foo *); f(NULL); The problem doesn't lie with NULL itself; it lies with the poor design of overloading these functions. I've probably made a hash of describing the article. I'll butt out now. Angus

Angus Leeming wrote:
The point of the article still holds, I think. You have your NULL class. Does it help here? Don't think so...
void f(string *); void f(foo *); f(NULL);
What if there were a template version of null added? For instance: void f ( int * ); void f ( char * ); f ( null<int> ); Would this solve the ambiguity, or is there something else that I am missing? -Jason

Somewhere on Shadow Earth, at Fri, Jan 21, 2005 at 09:44:49AM -0500, Jason Hise wrote:
Darren Cook wrote:
Heh. Have you read what Scott Meyers has to say about this?
Indeed I have not. Where could I find what he has to say about this?
Item 25 of Effective C++. Definitely worth reading all three of his Effective books. Not just lots of useful advice but also a pleasure to read.
Looks like I'll be buying them then :)
Well, I have heard that he is revising Effective C++. I can't say for certain, and his website doesn't say, but I thought I heard him say it at a talk or some such. Just an FYI. Personally, I have bought and paid for the first two editions, and plan to get the third, as well. -- Timothy Knox <mailto:tdk@thelbane.com> The one thing I've learned about freedom of expression is that you really ought to keep that sort of thing to yourself. -- Scott Adams, _I'm Not Anti-Business, I'm Anti-Idiot_

David B. Held wrote:
Jason Hise wrote:
Just wondering if there was any interest in a better null, or if such a thing existed in boost already. The code is relatively simple: [...]
Heh. Have you read what Scott Meyers has to say about this?
Also, the standard committeee paper N1601 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf) by Herb Sutter and Bjarne Stroustrup: #ifndef CPP0x_NULLPTR_N1601 #define CPP0x_NULLPTR_N1601 #if(__cplusplus <= 199711) // C++98 // A library implementation of N1601: provide nullptr semantics namespace std { class nullptr_t { void operator&() const; // address of nullptr cannot be taken public: template< typename T > operator T *() const // non-member pointer { return 0; } template< typename C, typename T > operator T C::*() const // member pointer { return 0; } }; } //__declspec(selectany) extern const std::nullptr_t nullptr; #endif #endif where: #include <iostream> #include <typeinfo> #include <nullptr> void f( char * ) { std::cout << "f( char * )\n"; } void f( int ) { std::cout << "f( int )\n"; } template< typename T > void g( T t ) { std::cout << "g( " << typeid(T).name() << " )\n"; } int main() { char * ch = nullptr; char * ch2 = 0; char * ch3 = true ? nullptr : nullptr; int n2 = 0; if( ch == 0 ) std::cout << "ch == 0\n"; if( ch == nullptr ) std::cout << "ch == nullptr\n"; if( ch ) std::cout << "ch\n"; if( n2 == 0 ) std::cout << "n2 == 0\n"; if( sizeof( nullptr ) == sizeof( void * )) std::cout << "sizeof( nullptr ) == sizeof( void * )\n"; std::cout << "typeid(nullptr).name() = " << typeid(nullptr).name() << '\n'; try{ throw nullptr; } catch( int ){ std::cout << "caught an integer\n"; } catch( std::nullptr_t ){ std::cout << "caught null pointer type!\n"; } try{ throw 0; } catch( std::nullptr_t ){ std::cout << "caught null pointer type!\n"; } catch( int ){ std::cout << "caught an integer\n"; } f( nullptr ); // calls f( char * ) f( 0 ); // calls f( int ) g( 0 ); // T = int g( nullptr ); // T = nullptr_t g(( float * )nullptr ); // T = float * # if 0 // error cases: char * ch4 = true ? 0 : nullptr; int n = nullptr; int n3 = true ? nullptr : nullptr; int n4 = true ? 0 : nullptr; if( n2 == nullptr ) std::cout << "n2 == nullptr\n"; if( nullptr ) std::cout << "nullptr\n"; if( nullptr == 0 ) std::cout << "nullptr == 0\n"; nullptr = 0; nullptr + 2; # endif return 0; } results in: ch == 0 ch == nullptr n2 == 0 typeid(nullptr).name() = class std::nullptr_t caught null pointer type! caught an integer f( char * ) f( int ) g( int ) g( class std::nullptr_t ) g( float * ) Regards, Reece
participants (6)
-
Angus Leeming
-
Darren Cook
-
David B. Held
-
Jason Hise
-
Reece Dunn
-
Timothy Knox