Why is operator void not invoked with cast syntax?
The technical reason why is found in §12.3.2:
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.
The rationale is (likely) to allow §5.2.9/4 to work:
Any expression can be explicitly converted to type “cv void.” The expression value is discarded.
(void)expr
to suppose to do nothing for the resulting value of any expression, but if it called your conversion operator it wouldn't be discarding anything. So they ban the use of operator void
in conversions.
Why not make it ill-formed to have the conversion-type-id be void
? Who knows, but keep in mind it's not totally useless:
struct foo
{
operator void()
{
std::cout << "huh?" << std::endl;
}
};
typedef void (foo::*void_function)();
foo f;
void_function func = &foo::operator void;
(f.*func)(); // prints "huh"
f.operator void(); // also does (which you knew)
It is still technically potentially useful for something, so maybe that's rationale enough not to make it ill-formed.
Why doesn't new require a cast to the pointer even though malloc requires it?
Because when you're using new
, you (normally) use a "new expression", which allocates and initializes an object. You're then assigning the address of that object to a pointer to an object of the same (or parent) type, which doesn't require a cast. A normal new expression (i.e., not a placement new) will invoke operator new
internally but the result of the new expression is not just the result from operator new
.
If you invoke operator new
directly, then you need to cast its result to assign the return value to a non-void pointer, just like you have to do with the return from malloc
.
Why operator void*() conversion function added to the C++ stream classes?
A feature of std::stringstream
is that it is intended that if the stream is used as a bool
, it gets converted to true
if the stream is still valid and false
if it's not. For instance this lets you use a simple syntax if you implement your own version of lexical cast.
(For reference, boost
contains a template function called lexical_cast
which does something similar to the following simple template function.)
template <typename T, typename U>
T lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
throw bad_lexical_cast();
}
}
If for instance, you work on a project where exceptions are disallowed, you might want to roll the following version of this instead.
template <typename T, typename U>
boost::optional<T> lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
return boost::none;
}
}
(There are various ways the above could be improved, this code is just to give an example.)
The operator void *
is being used in the above as follows:
ss << u
returns a reference toss
.- The
ss
is implicitly converted tovoid *
which isnullptr
if the stream operation failed, and non-null if the stream is still good. - The
&&
operator aborts quickly, depending on the truth value of that pointer. - The second part
ss >> t
runs, and returns and is also converted tovoid *
. - If both operations succeeded then we can return the streamed result
t
. If either failed then we signal an error.
The bool conversion feature is basically just syntactic sugar that allows this (and many other things) to be written concisely.
The drawback of actually introducing an implicit bool conversion is that then, std::stringstream
becomes implicitly convertible to int
and many other types also, because bool
is implicitly convertible to int
. This ultimately causes syntactic nightmares elsewhere.
For instance, if std::stringstream
had an implicit operator bool
conversion, suppose you have this simple code:
std::stringstream ss;
int x = 5;
ss << x;
Now in overload resolution, you have two potential overloads to consider (!), the normal one operator<<(std::stringstream &, int)
, and the one in which ss
is converted to bool
, then promoted to int
, and the bit shift operator may apply operator<<(int, int)
, all because of the implicit conversion to bool
...
The workaround is to use an implicit conversion to void *
instead, which can be used contextually as a bool, but isn't actually implicitly convertible to bool or int.
In C++11 we don't need this workaround any more, and there's no reason that anyone would have explicitly used the void *
conversion, so it was just removed.
(I'm searching for a reference, but I believe that the value of this function was only specified up to when it should be nullptr
vs. when it should not be nullptr
, and that it was implementation defined what nonzero pointer values it might yield. So any code that relied on the void *
version and cannot be trivially refactored to use the bool
version would have been incorrect anyways.)
The void *
workaround is still not without problems. In boost a more sophisticated "safe bool" idiom was developed for pre-C++11 code, which iiuc is based on something like T*
where T
is either a "type-used once", like a struct which is defined in the class implementing the idiom, or using a pointer-to-member function for that class and using return values which are either a particular private member function of that class, or nullptr. The "safe bool" idiom is used for instance in all of the boost smart pointers.
Regardless this whole mess was cleaned up in C++11 by introducing explicit operator bool
.
More info here: Is the safe-bool idiom obsolete in C++11?
Cast instance to void?
The "cast to void", however it is spelled, is a discarded value expression. It does not constitute a conversion, and therefore does not consider conversion functions.
C++ allows you to do lots of things that are pointless; it would be harder to forbid some special cases than to just leave the rules general.
Why does the type cast of malloc in C have the * symbol on the right and not on the left?
That's because when declaring a pointer the "*" is on the left, not on the right.
The *
is on the right of the type name. In void *p = &a;
type is void *
, a void pointer. It is on the left of the thing it's being applied to, the variable p
.
In ptr = (cast-type*) malloc(byte-size)
the type is cast-type *
, the *
is to the right of the type name. The cast is on the left of the thing being cast, the call to malloc, like an adjective.
[I do find it odd that we write type *variable
, which makes it seem like the *
is part of the variable
rather than type* variable
which puts the *
with the type.]
What does operator void* () mean?
No they are two different operators. The operator void*
function is a type casting function, while operator()
is a function call operator.
The first is used when you want to convert an instance of Foo
to a void*
, like e.g.
Foo foo;
void* ptr = foo; // The compiler will call `operator void*` here
The second is used as a function:
Foo foo;
void* ptr = foo(); // The compiler calls `operator()` here
Why does a direct cast fail but the as operator succeed when testing a constrained generic type?
I used this question as the basis for a blog article in October 2015. Thanks for the great question!
Could someone please explain why this is the case?
"Why" questions are hard to answer; the answer is "because that's what the spec says" and then the natural question is "why does the spec say that?"
So let me make the question more crisp:
What language design factors influenced the decision to make the given cast operator illegal on constrained type parameters?
Consider the following scenario. You have a base type Fruit, derived types Apple and Banana, and, now comes the important part, a user-defined conversion from Apple to Banana.
What do you think this should do when called as M<Apple>
?
void M<T>(T t) where T : Fruit
{
Banana b = (Banana)t;
}
Most people reading the code would say that this should call the user-defined conversion from Apple to Banana. But C# generics are not C++ templates; the method is not recompiled from scratch for every generic construction. Rather, the method is compiled once, and during that compilation the meaning of every operator, including casts, is determined for every possible generic instantiation.
The body of M<Apple>
would have to have a user-defined conversion. The body of M<Banana>
would have an identity conversion. M<Cherry>
would be an error. We cannot have three different meanings of an operator in a generic method, so the operator is rejected.
Instead what you have to do is:
void M<T>(T t) where T : Fruit
{
Banana b = (Banana)(object)t;
}
Now both conversions are clear. The conversion to object is an implicit reference conversion; the conversion to Banana is an explicit reference conversion. The user-defined conversion is never called, and if this is constructed with Cherry then the error is at runtime, not compile time, as it always is when casting from object.
The as
operator is not like the cast operator; it always means the same thing no matter what types it is given because the as
operator does not ever invoke a user-defined conversion. Therefore it can be used in a context where a cast would be illegal.
Why type inference and implicit operator is not working in the following situations?
Your second question is why the implicit conversion from ()=>""
to V<string>
does not succeed, even though ()=>""
is convertible to Func<string>
and Func<string>
is convertible to V<string>
.
Again, I do not know how to answer "why not?" questions but I do know how to answer the question "what line of the specification indicates that the compiler ought to reject this code?" The relevant line is:
First, if required, performing a standard conversion from the source type to the operand type of the user-defined or lifted conversion operator.
Note that there is a small error here; this should say performing a standard conversion from the source expression. The source expression may not have a type. I believe I gave that note to the spec maintainer before I left the team, so hopefully this will get fixed in the next edition.
Anyway, it should now be clear what is going on here. There is no standard conversion from a lambda to a delegate type, and therefore the user-defined conversion is classified as inapplicable by the conversion resolution algorithm.
Related Topics
How to Use Std::Imbue to Set the Locale for Std::Wcout
Generate Include File Name in a MACro
Write a File in a Specific Path in C++
C++ Overloaded Function as Template Argument
Execute C++ from String Variable
Changing the Directory from Inside a C Program Under Windows Using System Command
Better Shading on Bw Display While Rendering Filled Surfaces
Initializing the Size of a C++ Vector
Why Is "Operator Void" Not Invoked with Cast Syntax
Uses for Negative Zero Floating Point Value
Is It Ok to Use C-Style Cast for Built-In Types
Can Sfinae Detect Private Access Violations
Distinguish Between Single and Double Click Events in Qt