Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

nullptr placeholder without #define

487 views
Skip to first unread message

marcin...@gmail.com

unread,
Mar 4, 2009, 9:08:32 PM3/4/09
to
Hi all,

I'm a little alergic to #define so when I wanted to make myself a
placeholder
for nullptr keyword for C++0x compability I came up with something
like this:

const struct nullptr_t {
template<class T>
operator T*() const { return 0; }
template<class T, class U>
operator T U::*() const { return 0; }
} nullptr = {};

template<class T>
bool operator==(T* lhs, const nullptr_t rhs) { return lhs == 0; }

template<class T>
bool operator==(const nullptr_t lhs, T* rhs) { return rhs == 0; }

template<class T, class U>
bool operator==(T U::* lhs, const nullptr_t rhs) { return lhs ==
0; }

template<class T, class U>
bool operator==(const nullptr_t lhs, T U::* rhs) { return rhs ==
0; }

It does not pass only one from Basic Cases from n2431:

if( nullptr == 0 ); // error

On GCC 4.3.3 it compiles.
On MinGW-GCC 3.4.5 it crushes the compiler.

I didn't do tests for other compilers nor Advanced Cases from n2431.

Ofcourse while reading n2431 for tests I've found that this is
proposed alternate solution (library implementation instead of
keyword).

Nevertheless I thought that it could interest people as alergic go
#define as I am and who didn't read said C++0x proposal.

Cheers
Sfider

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Joe Smith

unread,
Mar 5, 2009, 5:12:44 AM3/5/09
to

<marcin...@gmail.com> wrote:
>
> I'm a little alergic to #define so when I wanted to make myself a
> placeholder
> for nullptr keyword for C++0x compability I came up with something
> like this:
>
> [snip]

>
> It does not pass only one from Basic Cases from n2431:
>
> if( nullptr == 0 ); // error
>
> On GCC 4.3.3 it compiles.
> On MinGW-GCC 3.4.5 it crushes the compiler.

These are GCC issues. Comeau C++ rightly rejects that with a reasonable
error.

Indeed, all the test cases in N2431 (basic and advanced) pass with your
implementation under Comeau C++.

One minor nit. You should add a member of type "void* const" to the class,
preferably with a implementation reserved name like _Val. (Yes, this is not
allowed by the standard, but no real implementation should have issue with
that, and if anybody tries to access the member the use of such naming
should make it clear that something is wrong).

By doing that, you gain sizeof(nullptr)==sizeof(void*) as required in the
draft, without adding any other overhead.

In summary:


const struct nullptr_t {
template<class T>
operator T*() const { return 0; }
template<class T, class U>
operator T U::*() const { return 0; }

void* const _Val; //NEW
} nullptr = {};

(keep the operator== overloads of course).

Then the only issue left is the fact that nullptr_t really belongs in
namespace std.

Since (despite the standard) most compilers support users adding things to
namespace std at the slight risk of breaking things (which this would most
likely not do), I would wrap all that in a "namespace std{/*...*/}" block,
and add a "using ::std::nullptr;" statement at the end.

I think the combination of all of that simulates nullptr as closely as
possible in (real world) C++03.

marcin...@gmail.com

unread,
Mar 6, 2009, 3:22:57 AM3/6/09
to
On 5 Mar, 11:12, "Joe Smith" <unknown_kev_...@hotmail.com> wrote:
> These are GCC issues. Comeau C++ rightly rejects that with a reasonable
> error.
One other issue of GCC (MinGW-GCC 3.4.5 wich is not supported anymore)
is the inability to use this implementation for pointers to member functions.
The real problem here is that I do not know of better free C++ compiler
for windows and am stuck with it. And I'm stuck with using '0' wich now is:

#define nullptr 0

> One minor nit. You should add a member of type "void* const" to the class,
> preferably with a implementation reserved name like _Val. (Yes, this is not
> allowed by the standard, but no real implementation should have issue with
> that, and if anybody tries to access the member the use of such naming
> should make it clear that something is wrong).

I think that more proper solution would be making it private.

> Since (despite the standard) most compilers support users adding things to
> namespace std at the slight risk of breaking things (which this would most
> likely not do), I would wrap all that in a "namespace std{/*...*/}" block,
> and add a "using ::std::nullptr;" statement at the end.

I realy did not intend to simulate nullptr in such detail but it won't
hurt I suppose.

Current version looks like this:

const class nullptr_t {
public:


template<class T>
operator T*() const { return 0; }
template<class T, class U>
operator T U::*() const { return 0; }

private:
void* p;

void operator&() {}
} nullptr = nullptr_t();

nullptr should be constant (or more specifically it should be a literal)
and obtaining its address shouldn't be possible. I've also overloaded
operator!= ;).

It's a pity I cannot use it though...

Cheers
Sfider

Marsh Ray

unread,
Mar 6, 2009, 7:13:48 AM3/6/09
to
On Mar 5, 4:12 am, "Joe Smith" <unknown_kev_...@hotmail.com> wrote:
> [] You should add a member of type "void* const" to the class,

> preferably with a implementation reserved name like _Val. (Yes, this is
not
> allowed by the standard, but no real implementation should have issue with
> that, and if anybody tries to access the member the use of such naming
> should make it clear that something is wrong).

Just curious, is there a benefit to giving it a reserved name over
giving it a descriptive name like 'unused_dummy_for_size_equivalence_'
and making it private?

- Marsh

Triple-DES

unread,
Mar 6, 2009, 11:21:55 PM3/6/09
to
On 6 Mar, 09:22, "marcin.sfi...@gmail.com" <marcin.sfi...@gmail.com>
wrote:

> I realy did not intend to simulate nullptr in such detail but it won't
> hurt I suppose.
>
> Current version looks like this:
>
> const class nullptr_t {
> public:
> template<class T>
> operator T*() const { return 0; }
> template<class T, class U>
> operator T U::*() const { return 0; }
>
> private:
> void* p;
>
> void operator&() {}
>
> } nullptr = nullptr_t();
>
> nullptr should be constant (or more specifically it should be a literal)
> and obtaining its address shouldn't be possible. I've also overloaded
> operator!= ;).

Your nullptr still has a few semantical differences from the C++0x
equivalent per the latest draft:

if(nullptr); // implicit conversion to bool

Solution: operator bool() const { return false; }

nullptr_t(0); // conversion from integral null pointer
// constant to nullptr_t

Solution: declare a private nested (incomplete) type Z, and a ctor
accepting a pointer to Z. Unfortunately, the class will no longer
support an initializer with braces, which nullptr_t does.

reinterpret_cast<int>(nullptr); // nullptr_t can be explicitly
// converted to integral types

Solution: Seemingly impossible.

I think that's almost as close as you can get :)

Nikola Smiljanić

unread,
Mar 7, 2009, 12:03:59 AM3/7/09
to
On Mar 6, 9:22 am, "marcin.sfi...@gmail.com" <marcin.sfi...@gmail.com>
wrote:

> The real problem here is that I do not know of better free C++ compiler
> for windows and am stuck with it. And I'm stuck with using '0' wich now is:

Download Visual C++ Express 2008 and you'll have a much better
compiler that is also free.

Joe Smith

unread,
Mar 9, 2009, 4:19:40 AM3/9/09
to

Marsh Ray wrote:
> On Mar 5, 4:12 am, "Joe Smith" <unknown_kev_...@hotmail.com> wrote:
>> [] You should add a member of type "void* const" to the class,
>> preferably with a implementation reserved name like _Val. (Yes, this is
> not
>> allowed by the standard, but no real implementation should have issue
>> with
>> that, and if anybody tries to access the member the use of such naming
>> should make it clear that something is wrong).
>
> Just curious, is there a benefit to giving it a reserved name over
> giving it a descriptive name like 'unused_dummy_for_size_equivalence_'
> and making it private?

With a private variable the type cannot be initalized with braces (non-POD).
But otherwise, no benefit I am aware of.

Triple-DES

unread,
Mar 9, 2009, 7:13:56 AM3/9/09
to
On 6 Mar, 13:13, Marsh Ray <marsh...@gmail.com> wrote:
> On Mar 5, 4:12 am, "Joe Smith" <unknown_kev_...@hotmail.com> wrote:
>
> > [] You should add a member of type "void* const" to the class,
> > preferably with a implementation reserved name like _Val. (Yes, this is
> not
> > allowed by the standard, but no real implementation should have issue with
> > that, and if anybody tries to access the member the use of such naming
> > should make it clear that something is wrong).
>
> Just curious, is there a benefit to giving it a reserved name over
> giving it a descriptive name like 'unused_dummy_for_size_equivalence_'
> and making it private?

Yes, a class with private (non-static) data members is not an
aggregate (and consequently, not POD)

0 new messages