Reputation: 125
When I try to compile this code:
#include <iostream>
namespace Direction
{
enum Enum { UP, DOWN, LEFT, RIGHT };
}
using namespace std;
void move(int pDir);
int main()
{
printf("UP: %u\n", Direction::UP);
printf("DOWN: %u\n", Direction::DOWN);
printf("LEFT: %u\n", Direction::LEFT);
printf("RIGHT: %u\n", Direction::RIGHT);
move(Direction::UP);
return 0;
}
void move(int pDir)
{
printf("Move: ");
switch(pDir)
{
case(Direction::UP):
printf("UP");
break;
case(Direction::DOWN):
printf("DOWN");
break;
case(Direction::RIGHT):
printf("RIGHT");
break;
case(Direction::LEFT):
printf("LEFT");
break;
default:
printf("nothing");
break;
}
}
The result I expect would be:
UP: 0
DOWN: 1
LEFT: 2
RIGHT: 3
Move: UP
Instead the result is:
UP: 0
DOWN: 1
LEFT: 2
RIGHT: 3
It seems like void move(..)
just gets ignored.
I already found the problem: It's the using namespace std
. When I delete it, I get the result as expected.
So I have three questions:
1) Why does void move(..)
just gets "ignored"
2) Why can I access the members of Direction within the first four lines of int main()
3) How can I fix this? ,_,
Have a nice day my friends.
ps: This is an extracted example of my problem, on my project I need to use the namespace std.
Upvotes: 3
Views: 72
Reputation: 22890
Your move function application has been reviewed and unfortunately, a better application has been found. Please don't hesitate to reach us for comments or questions.
std::move in utility header is the function being called in this situation. This is due to multiple factors :
using namespace std
, any function definition in the std namespace is now candidate for overload resolution in the global scope (see Namespace scope). Direction::UP
is a rvalue, and the signature of std::move is template< class T >constexpr typename std::remove_reference<T>::type&& move( T&& t ) noexcept;
. T can resolve to the enum type without conversion.void move(int pDir);
and will require an implicit conversion from Direction::Enum&&
to int
When you remove on of these condition your function will be called. For instance
move((int)Direction::UP);
remove the need for an implicit conversion.
Upvotes: 2
Reputation: 2241
Due to your using namespace std
both move
(yours) and std::move
are now accessible through the name move
and when you call it, the usual overload resolution takes place, so the compiler checks whether
move(int)
or
template<typename T> move(T) // bit simplified here
is a better match for your call move(Direction::UP)
. Since the underlying type (aka std::underlying_type
) of an unscoped enum is implementation defined, it may be a char
or short
(or anything else), in which case the second candidate is a better match.
Other factors (like the rvalue-ness mentioned by UmNyobe) and the namespace of the arguments can as well have an influence on overload resolution. Moving the definition of your move
into the Direction
namespace for example should lead to the first candidate being called, since ADL (argument dependent lookup) kicks in, although I am not 100% sure on that right now.
So my advice, as already suggested by the others, is to avoid using namespace
as much as possible, at least at file scope. If you need to access a lot of stuff from one namespace, simply put the using namespace
into the function that requires it. Regarding namespace std
in particular, I highly recommend to never use using namespace std
.
Upvotes: 2