l. schwarz
l. schwarz

Reputation: 125

Using two namespaces only works partly

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

Answers (2)

UmNyobe
UmNyobe

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 :

  • The utility header is included by iostream, so it is defined in your code
  • Because of using namespace std, any function definition in the std namespace is now candidate for overload resolution in the global scope (see Namespace scope).
  • The argument 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.
  • Yours is 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

nh_
nh_

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

Related Questions