我正在编写一些C ++代码。在这些代码中,有嵌套的名称空间,例如A :: B :: C。 A,B,C是名称空间。我在A中定义了TYPEA类型,然后在B中再次定义了TYPEA。根据我的理解,A :: B :: TYPEA将屏蔽A :: TYPEA。但是为什么我仍然在函数的返回类型中添加名称空间前缀A :: B :: TYPEA?
namespace A
{
typedef int TYPEA;
namespace B
{
class ClassB
{
public:
typedef int TYPEA;
TYPEA foo();
};
ClassB::TYPEA ClassB::foo()
{
// ...
}
}
}
根据我的理解,A :: B :: ClassB :: TYPEA将屏蔽A :: TYPEA,为什么我不能这样定义foo:
TYPEA ClassB::foo()
{
// ...
}
答案 0 :(得分:2)
这只是C ++名称查找的规则之一。函数的前导返回类型不在该函数的范围内,因此在这种情况下,编译器不会在TYPEA
的范围内搜索名称ClassB
。
一个 trailing 返回类型在函数的范围内,因此TYPEA
将在ClassB
的范围内使用尾随返回:
auto ClassB::foo() -> TYPEA
{
// ...
}
答案 1 :(得分:0)
由于作用域,TYPEA
在类声明和方法定义内的任何地方都被认为A::B::ClassB::TYPEA
,在命名空间A::TYPEA
内的其他地方都被认为A
。
namespace A
{
typedef int TYPEA;
namespace B
{
/*
TYPEA refers to A::TYPEA
*/
class ClassB
{
public:
typedef int TYPEA;
TYPEA foo();
/*
TYPEA refers to A::B::ClassB::TYPEA
*/
};
/*
TYPEA refers to A::TYPEA
*/
ClassB::TYPEA ClassB::foo()
{
// ...
/*
TYPEA refers to A::B::ClassB::TYPEA
*/
}
};
/*
TYPEA refers to A::TYPEA
*/
}
}
根据我的理解,A :: B :: ClassB :: TYPEA将屏蔽A :: TYPEA,为什么我不能这样定义foo:
TYPEA ClassB::foo() { // ... }
实际上,对于您的特定情况,您可以。由于两个TYPEA
的类型都定义为int
,因此代码将编译是否为返回类型加上ClassB
前缀。
ClassB::TYPEA ClassB::foo() {}
// resolves to
// int ClassB::foo() {}
----
TYPEA ClassB::foo() {}
// resolves to
// int ClassB::foo() {}
两个签名是相同的。现在,如果相反的类型是 different ,那么签名将无法解析,并且会出现编译错误。例如:
namespace A
{
typedef double TYPEA; // double
namespace B
{
class ClassB
{
public:
typedef int TYPEA; // int
TYPEA foo();
};
ClassB::TYPEA ClassB::foo() // not the same as `TYPEA ClassB::foo()` !!!
{
// ...
}
}
}
在这里,需要使用名称空间前缀来消除TYPEA
的歧义并在ClassB
下指定一个类型定义的类型。