为什么在函数的返回类型之前需要添加名称空间前缀?

时间:2019-06-12 05:45:15

标签: c++

我正在编写一些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()
{
    // ...
}

2 个答案:

答案 0 :(得分:2)

这只是C ++名称查找的规则之一。函数的前导返回类型不在该函数的范围内,因此在这种情况下,编译器不会在TYPEA的范围内搜索名称ClassB

一个 trailing 返回类型在函数的范围内,因此TYPEA 将在ClassB的范围内使用尾随返回:

auto ClassB::foo() -> TYPEA
{
    // ...
}

Demo

答案 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下指定一个类型定义的类型。