Why NULL is converted to string*? - c++

I saw the following code:
class NullClass {
public:
template<class T> operator T*() const { return 0; }
};
const NullClass NULL;
void f(int x);
void f(string *p);
f(NULL); // converts NULL to string*, then calls f(string*)
Q1> I have problems to understand the following statement
template<class T> operator T*() const { return 0; }
Specially, what is the meaning of operator T*()?
Q2> Why f(NULL) is finally triggering the f(string*)?
Thank you

what is the meaning of operator T*()?
It is a user-defined conversion operator. It allows an object of type NullClass to be converted to any pointer type.
Such conversion operators can often lead to subtle, unexpected, and pernicious problems, so they are best avoided in most cases (they are, of course, occasionally useful).
Why f(NULL) is finally triggering the f(string*)?
NULL is of type NullClass. It can't be converted to an int, but the user-defined conversion NullClass -> T* can be used to convert it to a string*, so void f(string*) is selected.
Note that this works because there is only one overload of f that takes a pointer. If you had two overloads,
void f(int*);
void f(float*);
the call would be ambiguous because the NullClass -> T* conversion can be converted to both int* and float*.

template<class T> operator T*() means that there is an implicit conversion from NullClass to T* for any T.
When you're calling f(NULL), the compiler needs to decide which overload to use. Since neither overload takes an object of type NullClass, it looks which implicit conversions exist. There is no conversion to int, but there is one to string*, so the conversion is applied and the string* overload is called.

operator Anything() overloads the "cast" operator. Whenever NullClass needs to be converted to Anything, this function will be called, and the result will be used.
In your case, Anything is T* where T can be any type (it is a template parameter), meaning a NullClass supports casting to any pointers.
Since NullClass can be cast into any pointers, including a string*. So the f(string*) version will be used.

Q1> I have problems to understand the following statement
template<class T> operator T*() const { return 0; }
Specially, what is the meaning of operator T*()?
It's an implicit conversion operator. It makes it possible to have objects of the type it belongs to implicit convert to the target type T* here. This version is a special one, since, being a template, it can convert an object of that NullClass to any pointer type.
Implicit conversion are frowned upon for good reasons. They have the bad habit of kicking in at unexpected moments, making the compiler call an unintended version of an overloaded function. Having a templatized implicit conversion operator is especially evil because templatization multiplies the possibilities.
Q2> Why f(NULL) is finally triggering the f(string*)?
See above. There is no possible conversion to int, so the implicit conversion operator kicks in and converts an NullClass object into any pointer requested.
I suppose this is intended. Usually you don't want a pointer to be converted to an integer, which is why that class has an implicit conversion into any pointer, but none to int.
That NullClass isn't all that bad, but the NULL instance of it is pure stupidity. As soon as you include any of the many headers that define the NULL macro (defined to be 0, i.e. an integer constant), the preprocessor will trample over all source and replace each usage of NULL with 0. Since you can't avoid to include this, this error renders the whole class pretty much useless.

The NuLLClass provides a conversion function to convert to a pointer. When you call f(NULL), it will try to find a way to convert NULL to a valid argument for f.
Because you can call operator T*() on NULL, it will with T=string. This fulfills the demand for f(string *). Since there is no way to convert NULL to an int, there is only one clear choice of which function to call.

Specially, what is the meaning of operator T*()?
It is a conversion operator to type T*. It allows operations such as (T*)NULL.
Q2> Why f(NULL) is finally triggering the f(string*)?
Because the compiler looks for the best match between the arguments and the method's signature, in this case choosing template<typename T> NullClass::operator T*(), where T=string.

Related

typedef shared_ptr<T> conversion to bool

I have a typedefined shared_ptr<> which I am using in a conditional check.
This is how it is defined:
typedef std::shared_ptr<T> typeTPtr;
Then I am passing it to a function taking a bool argument:
void Foo(bool);
When I try to do:
typeTPtr ptrT = ...
Foo(ptrT);
I get the error an error saying
cannot convert argument from T to bool
I believe std::shared_ptr has bool operator explicitly defined.
Why is the compiler not converting shared_ptr to bool?
I am using Visual C++ 2017
Thank you.
It indeed does have an operator bool, but this operator is explicit, so you should perform a cast:
foo(static_cast<bool>(ptr));
Note that there is no need for a cast inside of if statement because it is considered an explicit conversion.
The operator bool() of shared_ptr is marked explicit. So implicit conversions are not possible.
Use a static_cast instead for explicit conversion.

Why is this cast ambiguous?

I have a class that I have written which does type erasure. The public interface is:
template <typename T>
value(const T &t);
value(value &&v);
template <typename T>
operator T() const;
When I create a value instance from a std::string I have no problems, everything works as expected. When I try to get the std::string back out, using static_cast<std::string>(val), where val is an instance of value that is holding a std::string, I get the following error from VS2012:
error C2440: 'static_cast' : cannot convert from 'value' to std::string'
No constructor could take the source type, or constructor overload resolution was ambiguous
If I comment out the templated cast operator and add operator std::string() const then it compiles. I figure that something between the std::string constructors and the templated cast operator have the same goodness of match. Could anyone suggest what is happening and how to fix it?
Igor explained the problem. Here's my suggested solution:
Your class is obviously only intended to store one type of object at a time, so make that explicit. Replace the conversion functions with a real function:
template <typename T>
T get() const;
Now call it like this:
std::string myString = myValue.get<std::string>( );
No ambiguity. No chance of the wrong function being called and messing everything up. And I'd argue that it is now more readable.
std::string has several constructors capable of being called with one parameter - e.g. one taking const string&, and another taking const char*. What should T resolve to, then?
From the C++ standard:
5.2.9p4 Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t.
In your case, the declaration std::string t(val); is ill-formed.
Following works with std::string (if you can return a reference).
static_cast<const std::string&>(val);

c-style type cast and operator()

Question was changed!
I use a simple way to hide my enums from local namespaces - enumeration inside of a struct. It goes roughly like this:
struct Color
{
enum Type
{
Red, Green, Black
};
Type t_;
Color(Type t) : t_(t) {}
operator Type () const {return t_;}
private:
template<typename T>
operator T () const;
};
operator T () is a protection from implicit type casting. Then I tried to compile this code with gcc and with keil:
Color n;
int a[9];
a[ (int)n ] = 1;
gcc compiled it with no error (wich is what I expected), but Keil gived me an error:
"invalid type conversion. operator () is inaccessible".
So my question is: which compiler is right?
I know about c++11 enum class, but it isn't supported by Keil now
Should reinterpret_cast (not c-style () cast) call type conversion operator?
No, reinterpret_cast is only used for a few dodgy types of conversions:
converting pointers to integers and back
converting between pointers (and references) to unrelated types
You shouldn't need a cast at all to use the implicit conversion operator - you have not prevented implicit conversion at all. In C++11, if the operator were explicit, then you'd need a static_cast.
If you're stuck with C++03, and you really want to prevent implicit conversion but allow explicit conversion, then I think the only sensible thing to do is to provide a named conversion function.
Update: The question has now changed, and is asking about C-style casting rather than reinterpret_cast. That should compile since any conversion that can be done by static_cast (including implicit conversions) can also be done with a C-style cast.

overloading non-member conversion to bool operator

I am trying to write bool-conversion operator for std::bitset
I tried:
template<size_t size>
operator bool(std::bitset<size> & b)
{
return b.any();
}
but I got
error C2801: 'mynamespace::operator bool' must be a non-static member
from my visual-studio.
But when I look up C2801 explanation it says nothing about conversion operators (only about =, ->, [],())
So, is it possible to somehow write "Conversion std::bitset to bool operator?"
(I can not call b.any() in my if-statements, because the same code must run when std::bitset is replaced with unsigned or something
typedef std::bitset<x> Bitset;
//typedef unsigned Bitset;
so the ideal syntax will be like:
Bitset b = whatewer;
if(b)
doStuff();
)
If this overloading is not possible, what is the recommended workaround?
so far I use it like:
if(b == Bitset(0))
doStuff();
but I dont like it.
Thank you
As the error message says, the conversion operator must be a non-static member of a class. That is true.
I can not call b.any() in my if-statements, because the same code must run when std::bitset is replaced with unsigned or something.
If that is your problem, then you can use function overload, and call it passing the argument which will return a boolean value:
template<typename T>
bool to_bool(T const & b)
{
return b; //implicit conversion (if allowed) for all other types
}
template<size_t N>
bool to_bool(std::bitset<N> const & b)
{
return b.any();
}
then use it as:
if (to_bool(whatever))
{
}
It will call the correct overload. If the type of whatever is std::bitset<N> then the second overloaded function will be called, or else the first one will be called.
§12.3.2/1: "A member function of a class X with a name of the form [...] specifies a conversion from X to the type specified..." (C++11 uses the same section number and nearly the same wording, adding only that the function takes no parameters).
The other possible way to define a conversion is a constructor (§12.3.1), which is obviously a class member as well.
In short, yes, conversions must always be defined as member functions.
One way to do what you want would be to write a wrapper around std::bitset that provides the conversion you care about:
template <int size>
class mybitest {
std::bitset<size> bits;
public:
operator bool() { return bits.any(); }
}
But if you decide to do that, you'll need to write forwarding functions for essentially all the pieces of bitset you're using (ctors, assignment, etc.)
The standard is a bit unclear on this (12.3.2):
A member function of a class X having no parameters with a name of the form [...] specifies a conversion from X to the type specified by the conversion-type-id. Such functions are called conversion functions. No return type can be specified. If a conversion function is a member function, the type of the conversion function (8.3.5) is “function taking no parameter returning conversion-type-id”.
The first sentence seems to imply that only member functions can be conversion functions, but I'm not sure what the purpose of the conditional "if a conversion function is a member function" is.
I'd take the first sentence as binding and conclude that a conversion function must be a member function.
in case this helps somebody, you can actually provide a not operator instead
template<size_t size>
operator !(std::bitset<size> & b)
{
return !b.any();
}
and use it like so using the !! idiom:
if (!!whatever)
{
}
still not ideal, but a bit closer I think.

Why cant i use two ptrs in operator overload?

This is annoying, i can write a function with these parameters/return, but why cant i define an operator to do this?
-edit- i am actually trying to overload << the below is just for reference.
From msdn
// C2803.cpp
// compile with: /c
class A{};
bool operator< (const A *left, const A *right); // C2803
// try the following line instead
// bool operator< (const A& left, const A& right);
gcc error
error: ‘bool operator<(const A*, const A*)’ must have an argument of class or enumerated type
Because every user-defined operator overload needs at least one user-defined type as a parameter. A point isn't a user-defined type.
C++03 standard, §13.5 [over.oper] p6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.
Because you aren't allowed to cheat.
If you could override comparison operators for pointer types, then you would no longer be able to compare those pointers by value (aka: by the actual numerical pointer values). And that's kind of important and occasionally useful.
My real code is actually <<. Why cant i use it for that?
For the same reason: pointers are C++-basic types. They aren't user-defined types. Do you want to be able to not left-shift pointer values anymore? OK, obviously you do, but C++ won't let you.
You can only override operators when C++ does not have existing functionality for operators with those types (with a few exceptions). C++ already has operator< and operator<< for pointers, so you're not allowed to change what they do.