当我尝试编译此代码时:
#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()
3)我该如何解决这个问题? ,_,
祝我朋友度过美好的一天。
ps:这是我问题的解压缩示例,在我的项目中我需要使用命名空间std。
答案 0 :(得分:2)
您的移动功能应用程序已经过审核,不幸的是,a 已经找到了更好的应用。请不要犹豫与我们联系 提出意见或问题。
std::move in utility header是在这种情况下被调用的函数。这是由多种因素造成的:
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
)是实现定义的,它可能是char
或short
(或其他任何东西),在这种情况下,第二个候选是更好的匹配。
其他因素(如UmNyobe提到的rvalue-ness)和参数的命名空间也可能对重载决策产生影响。例如,将move
的定义移动到Direction
名称空间应该会导致第一个候选者被调用,因为ADL(依赖于参数的查找)会启动,尽管我现在还不是100%肯定
所以我的建议,正如其他人已经建议的那样,是尽可能避免using namespace
,至少在档案范围内。如果您需要从一个名称空间访问很多东西,只需将using namespace
放入需要它的函数中。特别是关于命名空间std
,我强烈建议永远不要使用using namespace std
。