不同命名空间中相同的函数名

10
假设我有不同的命名空间,比如苹果命名空间和橙子命名空间,但是这两个命名空间都包含一个名为myfunction()的函数。

当我在主函数中调用myfunction()时会发生什么?


7
可能找不到这个名称并且代码无法编译。但是也许可以发布一些示例代码,因为细节很重要。 - juanchopanza
请在函数调用中明确指定您想要的命名空间,例如 apply::myfunction() 或 orange::myfunction()。 - acraig5075
2个回答

24

这正是命名空间的用途所在。

在您的main()函数中,或一般来说在全局命名空间中,您将能够选择要调用哪个myfunction

int main()
{
     apple::myfunction(); // call the version into the apple namespace
     orange::myfunction(); // call the orange one
     myfunction(); // error: there is no using declaration / directive
}

如果存在一个using指示符using namespace apple)或者一个using声明using apple::myfunction),则主函数的最后一行会调用命名空间apple中的版本。如果两个myfunction版本都在作用域内,则最后一行会再次产生错误,因为在这种情况下必须指定要调用哪个函数。


如果你使用类似 using namespace apple using namespace orange 这样的东西呢?我想这就是完整答案的最后一部分了。 - Timo
在这种情况下,调用是不明确的,编译器必须拒绝它。 - M.M
如果你执行**using namespace apple; using namespace orange; int main(){ myfunction(...);}**,会得到一个编译器错误吗? - White Philosophy
6
为了完整起见,您可以补充说明,如果存在未命名空间的函数,并且您当前位于命名空间内,您可以编写 ::myfunction();。该语句的作用是调用未命名空间中的函数。 - Mr Lister
1
@MichaelGoh:如果函数签名足够不同,可以区分它们并且调用一个函数是正确的而另一个不正确,那么就没有歧义。如果签名相同或相似,则调用是有歧义的。 - Jonathan Leffler
显示剩余2条评论

5
考虑下面的例子。
namespace Gandalf{

    namespace Frodo{
         bool static hasMyPrecious(){ // _ZN7Gandalf5FrodoL13hasMyPreciousEv
            return true;
        }
    };

    bool static hasMyPrecious(){ // _ZN7GandalfL13hasMyPreciousEv
        return true;
    }
};

namespace Sauron{
    bool static hasMyPrecious(){ // _ZN5SauronL13hasMyPreciousEv
        return true;
    }
};

bool hasMyPrecious(){ // _Z13hasMyPreciousv
    return true;
}

int main()
{
    if( Gandalf::Frodo::hasMyPrecious() || // _ZN7Gandalf5FrodoL13hasMyPreciousEv
        Gandalf::hasMyPrecious()        ||  // _ZN7GandalfL13hasMyPreciousEv
        Sauron::hasMyPrecious()          || // _ZN5SauronL13hasMyPreciousEv
        hasMyPrecious()) // _Z13hasMyPreciousv
        return 0;

    return 1;
}

根据函数所在的命名空间,编译器会生成每个函数的唯一标识符,称为编码名称(Mangled Name),该名称是命名空间范围、函数名称、返回类型和实际参数的编码。当您调用这些函数时,每个函数调用都会查找相同的编码签名,如果找不到,则编译器报告错误。如果您对内部工作感兴趣,可以尝试使用 clang -emit-llvm -S -c main.cpp -o main.ll 进行实验。

2
请注意,标准并未指定任何名称混淆的样式,甚至在我看来它根本没有提到。你的例子对于G++是正确的,但MSVC使用不同的方式,而我想英特尔可能会用另一种方式。用例子说明是可以的,但应该明确指出,当这些例子不可移植、不符合标准时,你不能依赖这种行为,因为它是实现定义的。 - Elkvis
是的,@Elkvis指出了。作用域映射是实现定义的,并且随编译器而异。示例旨在说明作用域和作用域内的函数之间的关系。当然,NameLookUp算法会发生变化,可能是基于简单表格的!但最终我们要看的是具有相同名称的函数。并且可以通过clang轻松学习这些概念,因此这是最后的提示 :) - Mahesh Attarde
1
完全与编程无关,但“Soron”不应该是“Sauron”吗? - Matteo Tassinari
确实 ;) 你抓住我了! - Mahesh Attarde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接