in c++
void foo(int i)
{ std::cout<<"int"<<std::endl; }
void foo(float i)
{ std::cout<<"float"<<std::endl; }
void foo(void *i)
{ std::cout<<"void *"<<std::endl; }
void foo(bool b)
{ std::cout<<"bool"<<std::endl; }
void main() { foo(0); }
when compiling this, it makes error.
in visual-studio 2008, the error is C2668:'function' : ambiguous call to overloaded function
i know why this problem occur and i know a solution that using-time typecast. but i think this is not a good solution because using this way is kill the lexicality of function overloading.
in my project, i making a lexical-object that change auto type to int,float,std::basic_string and function pointer. overload all typecast operator and creator. but when i input a 'NULL', the error C2668 occurs.
in fact it is almost no problem . the only serious problem is when using FALSE. my project is core library and so i can't guide every end-client programmer.
who knows the trick or tip of solve this problem more smart way?
As it stands right now, your code should not cause an error -- there's no ambiguity. When passing 0 (an int), it's clear that foo(int) (identity conversion) is a better fit than any of the others (even though 0 can also be implicitly converted to the types for all the other overloads).
My immediate guess would be that the code you're testing isn't quite the same as you've posted. If, for example, you did not have the overload taking int, I'd expect a error about ambiguous overloads (since, as noted above, there are implicit conversions from 0 to the types taken by all the other overloads). I've confirmed that VC++ 2008 accepts the code as is (and so do VC 2010 and the beta of VC11 and g++ 4.7.0).
As an aside I'd note that main should really return an int (though it's almost certainly unrelated to the question at hand).
C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool.
Maybe you could define your FALSE to ((bool)0) instead of just 0 (why not use false instead?!).
Also, if you think about it, having f(int *) and f(char *) and calling f(NULL) is ambiguous, so you need a cast anyway! The compiler doesn't magically know your intentions unless you tell it. So if something is inherently ambiguous, you just have to make it unambiguous by casting.
Related
I have unearthed an old C++ DLL, and I'd like to us it in one of my projects, in VS2015.
The problem is, it does not compile. I got in touch with a guy in the team that made the code in the first place, and he is positive that the exact same code compiled with VS2010.
I have an error in an otherwise very simple function:
Extract of header:
/*
Data input
*/
istream* input; //Source of data
long inputpos; // Current position in the data stream
And the code itself:
// Helper function to increment a counter while reading a character
void* Calculator::inputstream_get(char& ch)
{
++inputpos;
return input->get(ch);
}
In the end, I get an Error C2440:
'return': cannot convert from 'std::basic_istream<char,std::char_traits<char>>' to 'void *'
It is my understanding (I'm not a C++ expert I have to say...) that void pointers could represent any type of data, am I mistaken?
Is there any way to 'cast' my istream to an void pointer?
Thanks a lot for your help
The reason why this compiles in VS 2010 (C++03) and not in VS 2015 (C++11) is that in C++03, standard library streams defined an implicit conversion to void*; the purpose of that conversion was to allow testing them for truthiness (such as while (cin >> x)) without allowing an implicit conversion to bool (which would allows such monstrosities as 1 + (cin >> x) to compile).
Note that the value of the returned void* was underspecified: it was either a null pointer when the stream is in a failed state, or an unspecified non-null pointer when the stram's in good state.
C++11 introduced the notion of explicit conversion operators and contextual conversion to bool, which means that these "hacky" conversions to void* were replaced in the standard by a safe explicit operator bool () const. Of course, this makes the code fail to compile as C++11.
How you can solve this is change Calculator::inputstream_get as follows:
void* Calculator::inputstream_get(char& ch)
{
++inputpos;
return input->get(ch) ? this : nullptr;
}
This preserves the semantics of returning a null pointer on failure, and an unspecified non-null pointer on success.
To answer your last question. You cannot cast a non pointer to a pointer. But you can cast any pointer to a void pointer with (void*)
This is the deal. http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool
In C++03 that was operator void* and in C++11 that is operator bool.
Change that void* to bool. Note that after the change the code will be not usable in C++03 compiler. You can solve it in a portable fashion with
if (input->get(ch)) return true;
else return false;
Actually, the most proper way is to return reference to the actual istream object.
Can you explain me what is the meaning of (void (*)(void *)) in the following expression:
(void (*)(void *))pthread_mutex_unlock
The outer brackets represent a cast. The stuff inside those brackets is the type to cast to.
In this case, it is a pointer to a function (*), taking a void* argument, and returning void (i.e. nothing).
It is used here to cast pthread_mutex_unlock, which has the signature
int pthread_mutex_unlock(pthread_mutex_t*);
such that it can be used (for example, as a callback) with something that expects a function of the type
void function(void*);
Note that the wisdom of doing this depends strongly on the platform being targeted. It would be safer (i.e. more portable) to wrap the function with another, of the correct signature
void pthread_mutex_unlock_wrapper(void *mutex)
{
pthread_mutex_unlock((pthread_mutex_t*)mutex);
}
this performs a cast to the argument type for pthread_mutex_unlock and discards the return type. This avoids the potential for stack corruption as a result of the caller and callee having a different understanding of the space requirements for arguments and return values (although in practice this may rarely be an issue for ignored return values, it is still better to be safe).
Endnote:
As a final note, since you tagged the question as C++, you could replace the (pthread_mutex_t*)mutex cast in the wrapper function with static_cast<pthread_mutex_t*>(mutex), which performs an equivalent conversion, but can be more easily read and understood to be a cast. If you're genuinely using C++, you should prefer these "C++ style" casts everywhere, since they have clearly defined semantics (i.e. there are limits to what you can static_cast, what you can dynamic_cast, etc.) and they are easier to spot when reading code.
It's a "C-style" cast to the type pointer-to-function taking a void* argument and not returning anything (with undefined behaviour due to the return type mismatch)....
Note that the type of pthread_mutex_unlock itself is:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
It was probably used let some code that knew how to call a function expecting a void* actually make callbacks to pthread_mutex_unlock, which will work on most compilers because the int return value is typically just kept in a register for the caller so ignoring it doesn't affect the stack layout or unwinding, but some compilers might crash.
Example:
template <typename T>
class On_Destruction
{
public:
On_Destruction(void(*f)(T), T t)
: f_(f), t_(t)
{ }
~On_Destruction() { f_(t_); }
private:
void (*f_)(void*);
T t_;
};
...in some function...
pthread_mutex_lock(my_mutex);
On_Destruction<void*> guard((void(*)(void*))pthread_mutex_unlock,
(void*)&my_mutex);
...unlock when unwinding stack by return/break/throw etc...
There are much better ways to do this that don't have undefined behaviour (due to bodgy casts)... e.g. using std::mutex and std::lock_guard.
This line is not "self sufficient"
"As is" it tells you that the pointer to the function pthread_mutex_unlock() would be cast to a:
pointer to a function taking a pointer to anything as argument and returning nothing.
I don't get it why? I don't think compatibility should be a problem as functions declared without the specifier actually have it implicitly defined to false. If it's about name mangling - can we just suppose that old one (existing) will imply noexcept(false) and add another new symbol to the mangling for noexcept(true).
This is going to be useful when working with templates as now comparing function type and noexcept specifier should be done seperatly. What I basically mean is this:
int func() noexcept(true), func_1() noexcept(false);
decltype(func) == decltype(func_1); //this now equals true
But on the other hand if we had function assignment by either using pointer or reference then - the noexcept specifier is checked as if it was part of the type:
int (&refFunc)() noexcept(true) = func_1; //target exception specification is not superset of source
int (&refFunc)() noexcept(true) = func; //ok
So for now implementing full function matching should be done by both performing type and noexcept check which is kinda complex:
decltype(func) == decltype(func_1) && noexcept(func()) == noexcept(func_1()); //this now equals false
Imagine if functions have got parameters:
int func(int, double) noexcept(true), func_1(int, double) noexcept(false);
decltype(func) == decltype(func_1) && noexcept(func(int{}, double{})) == noexcept(func_1(int{}, double{})); //this now equals false
Starting with C++17, the noexcept specifier is a part of the function type.
Reference
The noexcept-specification is a part of the function type and may
appear as part of any function declarator. (since C++17)
C/C++03 compatibility
One of most important C++ basic ideas is backward compatibility with C language and older C++ versions. And it works in most cases. Adding exceptions to function specifiers would deny this idea. There was no noexcept in C++03 and C and it would cause problems with function pointers and so on.
Low level
Let's have a think how function work in low level. They are basically jump with saved (on the stack) return address. They pass arguments and return values also via stack (not always, but let's simplify a bit). So, when you declare a function you actually tell how many bytes function should take from stack and how many it leaves on it. Function declaration is most of all telling the program what to EXPECT NORMALLY from function. Now, knowing that, do exceptions change anything in the information normally passed to/from function? They don't. And I think this is major reason why exceptions aren't part of type.
Edit:
In C++17 noexcept actually became part of the type system so you cannot do this:
void (*p)();
void (**pp)() noexcept = &p; //error here
The rationale behind this decision is, from what I know, allowing better optiization.
Think in a similar fashion like:
1. The bare name of an array is equivalent with the pointer to the first element, without the need to specify index 0.
2. toString() from Java makes it possible to use the name of an object as a string without calling any object method.
Now is there a way in C++ to use the name of a class object to refer to its first member?
Consider:
class Program
{
public:
int id;
char *str;
};
void function(int p)
{
//...
}
and then:
Program prog0;
function(prog0); // instead of function(prog0.id)
Any way to "hide" the member reference?
EDIT:
Why was the holyBlackCat's answer deleted? I was inclining to vote it as the best answer -- no offense, Mateusz. But he was the first to suggest conversion operator and the example was complete and simple.
In C++, such behaviour would be a cataclysm. If I understand correctly, Java tries to convert object of type A to object of type B by searching for first member in A, that is of type B or is implicitly convertible to B.
C++ wasn't designed that way. We like to write code, that is always predictable. You can achieve what you want, but for a price.
The best solution in this case would be conversion operator - consider:
class Program
{
public:
int id;
char *str;
operator int()
{
return this->id;
}
//You can have more than one!
operator const char*()
{
return this->str;
}
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}
Now it is possible to do the following:
Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)
The price is, that if you add another int and place it before id it will not be used in conversion, because we stated in our operator explicitly, that "int content" of our class is represented by id and this member is considered when it comes to such conversion.
However, even this simple example shows some potential problems - overloading functions with integral and pointer types could result in very unpredictable behavior. When type contains conversion operators to both pointers and integers, it can get even worse.
Assume, that we have following function:
void func(unsigned long)
{
}
And we call func with argument of type Program. Which conversion operator would you expect to be called? Compiler knows how to convert Program to either int or const char*, but not unsigned long. This article on cppreference should help you to understand how implicit conversions work.
Also, as Barry pointed out, more meaningless constructs become available. Consider this one:
int x = prog + 2
What does it mean? It is perfectly valid code, though. That is why conversion operators should be dosed extremely carefully (in pre-C++11 era, there was a general advise, that every class should have at most one such operator).
Quote from MSDN:
If a conversion is required that causes an ambiguity, an error is generated. Ambiguities arise when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.
Sometimes, simple solution to this problem is to mark conversion operator with explicit keyword, so you would need to change above calls to:
function_int((int)prog);
function_str((const char*)prog);
It is not as pretty as the previous form, but much safer. It basically means, that compiler is forbidden to perform any implicit conversion using operator marked as explicit. Very useful to avoid ambiguous calls, while still providing some flexibility in code - you can still very easily convert objects of one type to another, but you can be sure when and where these conversions are performed.
However, explicit conversion operators are still not supported by some compilers, as this is C++ 11 feature (for example, Visual C++ 11 doesn't support it).
You can read more about explicit keyword here.
Now is there a way in C++ to use the name of a class object to refer to its first member?
No, C++ doesn't have any reflection, so there's no way to actually determine what the "first member" is.
However, if what you really want is to get an ID for any object, you could just require that object to have that method:
template <typename T>
void function(const T& t) {
int id = t.getID();
// etc.
}
Without knowing more about your use-case, it's hard to know what to propose.
I transferred my code to Ubuntu 4.4.1 g++ compiler. While overloading operator ++ (int) as below, it throws error for (T*), but works fine for (T*&). In my earlier version (linux-64, but don't remember exact version) it was working fine with (T*) also.
Any reason, why ?
template<typename T>
struct Wrap
{
void *p; // Actually 'p' comes from a non-template base class
Wrap<T>& operator ++ ()
{
((T*)p) ++; // throws error; if changed to (T*&) then ok!
return *this;
}
// ...
};
int main ()
{
Wrap<int> c;
++c; // calling prefix increment
}
A result of a type-cast is not an lvalue, so it cannot be assigned to and (built-in) ++ is a form of assignment. It was a bug in the compiler if it ever worked.
With reference it compiles (in efect it's the same as *(T**)&p), but due to aliasing rules (compiler may assume that pointers (and references) of different types don't point to the same object) it is formally invalid, though it will work on all known compilers.
The cleanest way it to:
p = static_cast<void *>(static_cast<T *>(p) + 1)
(never use C-style cast in C++) and rely on the compiler being able to compile it exactly the same way as ++. However if you have the template argument available when defining the pointer (in the sample code you do), it's much better to just use properly typed pointer (I'd say it would also work with member pointers, but they don't have meaningful ++).
Looks like you mixing up your prefix and postfix increment signatures. Also, why use a void* if you know your type is T ?
See below for appropriate signatures:
http://www.codeguru.com/forum/showthread.php?t=231051