Why is it impossible to have a reference-to-void?
If you did have a reference to void, what would you do with it? It wouldn't be a number, or a character, or a pointer, or anything like that. Your hypothetical generic function couldn't perform any operation on it, except taking its address (and not its size).
"void" has two uses: to disclaim any knowledge of type (as in void *), and to specify nothing as opposed to something (void function return). In neither case is it possible to say anything about a void something except that it may have an address.
If you can't think of a way something can be useful, and I can't, that is at least evidence that something is useless, and that may well be at least part of the rationale here.
A reference is a reference to an instance of something.
An instance of something can't be of type void
.
Any instance of something must have a specific type (and possibly base types).
Here's a summary of the different things that have been said, and that I've thought of.
Two main reasons why reference-to-void are disallowed
1 They would have been totally useless.
Indeed, if we look back at the times of C, void pointers had two purposes:
- Memory management (e.g. malloc)
- Genericity (writing functions that can accept any type of arguments)
When C++ came out, templates became the best solution to implement genericity. However, custom memory management still had to be possible, and interoperability between C++ and C was a major concern, so void* was kept. An hypothetical void reference would be of no help with memory management, and genericity is already covered, so basically it would have almost no use (except for the guarantee of non-nullness described below).
2 You wouldn't be able to do anything with it
When using a void pointer, you're not allowed to dereference it; transposed to the case of references, that means you can't use the (always hypothetical) void reference. So
void *data = // something
// using *data and data-> is forbidden
void &data = // something
// using data is forbidden
However, we could think of a use case where the reference wouldn't have to be "dereferenced" (this phrase is awfully incorrect, but you get my point), but where we would only take its address . Let's assume I have the following function:
void foo(void *dataptr)
{
assert(dataptr != NULL); // or != 0
// do something with dataptr
}
To avoid this annoying assert, I could write the function this way:
void foo(void &dataref)
{
void *data = &dataref;
// do something with data
}
However, for this to work, &dataref
needs to be equivalent to dataptr
, which is not the case: &dataref
is equivalent to &*dataptr
!
Therefore, even taking the address implies a dereferencing, at least conceptually (behind the scenes, the first equivalence is probably true, but at the semantic level it is not). Consequently, there is absolutely no usage we can make of data, so void references are an aberration.
OK, one thing is bugging me about this. The idea of a void*
, as mentioned above, is that you still have a valid variable containing an address, but the type is being ignored. This seems allowable since we can still work with the address data - the type is somewhat superfluous (or less important) in this context. Dereferencing it is bad, because to try and access a member doesn't make sense e.g. p.mem
. We don't know what class to refer to, and thus the memory to jump to, the vtable pointers to follow.
However, it'd then seem to make sense that p
on its own would be OK since it'd only refer to the object, but none of its data. No class information is needed to do so, just the address. I understand there's absolutely no use for this, but it's important in defining when things break down. Allowing this notion, a C++ reference (constantly dereferenced but not accessing anything) e.g. void& ref = static_cast< &void >(obj)
also makes sense, and thus would allow void references. I'm not saying anyone should take it up with those in charge, but from a "making sense" point of view, it'd seem correct, no?
As Luc Touraille pointed out above (at least, this is my interpretation), it could be implemented, but the issue is a semantic one. The reasonable explanation I could come to was that since an object variable is a "tag" for a sequence of memory, the type is of important semantic value. Thus, the pointer, being thought of as a variable with an address value, treats the type as somewhat superfluous - not key to defining it.
Would anyone agree with that?