After writing `memset( &x, 0, sizeof( x ) );`

for the millionth time,
you might start to get lazy and decide it's a good idea to ```
#define
ZERO( p ) memset( p, 0, sizeof( *p ) );
```

. This turns out to be very easy
to misuse:

```
int x;
ZERO( &x ); // cool
int y[ 8 ];
ZERO( &y ); // cool
ZERO( y ); // y[ 0 ] = 0, no warnings
int * z = y;
ZERO( z ); // y[ 0 ] = 0
ZERO( &z ); // z = NULL
```

You can try things like making `ZERO`

take a pointer instead, but you
still always end up with cases where the compiler won't tell you that
you screwed up. The problem is that there's no way for `ZERO`

to do the
right thing to a pointer because it can't know how big the object being
pointed at is. The simplest solution is to simply not allow that:

```
template< typename T > struct IsAPointer { enum { value = false }; };
template< typename T > struct IsAPointer< T * > { enum { value = true }; };
template< typename T >
void zero( T & x ) {
static_assert( !IsAPointer< T >::value );
memset( &x, 0, sizeof( x ) );
}
```

and as a bonus, we can use the same trick from last time to make it work on fixed-size arrays too:

```
template< typename T, size_t N >
void zero( T x[ N ] ) {
memset( x, 0, sizeof( T ) * N );
}
```

Neat! (maybe)