使用两个名称空间仅部分工作

时间:2018-05-15 09:00:17

标签: c++ enums namespaces

当我尝试编译此代码时:

#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;
    }
}

我期望的结果是:

UP: 0
DOWN: 1
LEFT: 2
RIGHT: 3
Move: UP

相反,结果是:

UP: 0
DOWN: 1
LEFT: 2
RIGHT: 3

似乎void move(..)被忽略了。

我已经发现了问题:它是using namespace std。当我删除它时,我得到了预期的结果。

所以我有三个问题:

1)为什么void move(..)被忽略&#34;

2)为什么我可以在int main()

的前四行中访问Direction的成员

3)我该如何解决这个问题? ,_,

祝我朋友度过美好的一天。

ps:这是我问题的解压缩示例,在我的项目中我需要使用命名空间std。

2 个答案:

答案 0 :(得分:2)

  

您的移动功能应用程序已经过审核,不幸的是,a   已经找到了更好的应用。请不要犹豫与我们联系   提出意见或问题。

std::move in utility header是在这种情况下被调用的函数。这是由多种因素造成的:

  • 实用程序标头包含在 iostream 中,因此它已在您的代码中定义
  • 由于using namespace std,std命名空间中的任何函数定义都是now candidate for overload resolution in the global scope (see Namespace scope)
  • 参数Direction::UP是一个右值,std :: move的签名是template< class T >constexpr typename std::remove_reference<T>::type&& move( T&& t ) noexcept;。 T可以在不转换的情况下解析为枚举类型。
  • 您的void move(int pDir);,需要Direction::Enum&&int
  • 隐式转化

当您删除这些条件时,将调用您的函数。例如

move((int)Direction::UP);

不需要隐式转换。

答案 1 :(得分:2)

由于您的using namespace std move(您的)和std::move现在都可以通过名称move访问,当您调用它时,会发生通常的重载解析,所以编译器检查是否

move(int)

template<typename T> move(T) // bit simplified here

更适合您的通话move(Direction::UP)。由于未编译的枚举的基础类型(又名std::underlying_type)是实现定义的,它可能是charshort(或其他任何东西),在这种情况下,第二个候选是更好的匹配。

其他因素(如UmNyobe提到的rvalue-ness)和参数的命名空间也可能对重载决策产生影响。例如,将move的定义移动到Direction名称空间应该会导致第一个候选者被调用,因为ADL(依赖于参数的查找)会启动,尽管我现在还不是100%肯定

所以我的建议,正如其他人已经建议的那样,是尽可能避免using namespace,至少在档案范围内。如果您需要从一个名称空间访问很多东西,只需将using namespace放入需要它的函数中。特别是关于命名空间std,我强烈建议永远不要使用using namespace std