有没有办法将全局名称插入命名空间并使其仅从该命名空间中可用?

Dei*_*Dei 16 c++ namespaces c++11

假设我"C"在全局范围内具有链接功能.

extern "C" int fun(int);
Run Code Online (Sandbox Code Playgroud)

然后,如果我想让它在命名空间中可见,我会这样做:

namespace foo {
   using ::fun;
}
Run Code Online (Sandbox Code Playgroud)

但在此之后,我仍然能够称其为::fun(0)foo::fun(0).

所以我的问题是,有没有办法禁止从全局命名空间调用函数fun,只允许从中调用namespace foo

Chr*_*phe 11

该标准明确规定外部C函数在命名空间内声明,即使C不知道命名空间:

7.5/4:链接规范没有建立范围.链接规范仅在命名空间范围内发生.

因此,不是在全局命名空间中声明函数,而是可以直接在以下内容中定义它foo namespace:

// no declaration in global namespace, but... 
namespace foo {
    extern "C" int fun();
}
Run Code Online (Sandbox Code Playgroud)

然后,您只能通过命名空间引用此函数:

foo::fun();  // yes !
::fun();     // doesn't compile !!!
Run Code Online (Sandbox Code Playgroud)

请注意,您甚至可以在多个名称空间中声明外部C函数.它们都会引用相同的C函数:

namespace bar {
    extern "C" int fun();
}
...
foo::fun();  // ok
bar::fun();  // ok - same result as foo::fun(); 
Run Code Online (Sandbox Code Playgroud)

这是由标准保证:

7.5/6:最多一个具有特定名称的函数可以具有C语言链接.具有相同函数名称的C语言链接的函数的两个声明(忽略限定它的命名空间名称)出现在不同的命名空间范围内引用相同的函数.

请注意,如果由于某些特定约束而在一个编译单元的全局命名空间中声明了extern函数,您仍然可以组织在您将使用本地命名空间的其他编译单元中看不到此声明.根据上面的标准声明,这是完全有效的.但是,如果您在不同的编译单元中使用不同的可见性,则需要注意一些事项!


kfs*_*one 10

由于C语言没有名称空间,因此extern "C"说明符的一部分表示源名称没有名称空间.

因此,以下代码将调用该C函数foo:

namespace bar
{
    extern "C" void foo();
}

void foo() {}  // note: legal, so no pre-existing ::foo()

void caller() {
    bar::foo();  // calls the C function
}
Run Code Online (Sandbox Code Playgroud)

所以你可以做到

namespace bar
{
    extern "C"
    {
        #include "foo.h"
    }
}
Run Code Online (Sandbox Code Playgroud)

或者如果您需要与C代码共享它:

#ifdef __cplusplus
namespace bar
{
    extern "C"
    {
#endif
// .. C-compatible definitions etc
#ifdef __cplusplus
    }
}
#endif
Run Code Online (Sandbox Code Playgroud)


eca*_*mur 9

你可以这样做,因为C++ 11 在匿名内联命名空间中使用了一个模糊函数的删除声明:

inline namespace { int fun(int) = delete; }
Run Code Online (Sandbox Code Playgroud)

试图打电话::fun(0)fun(0)发出错误:

error: call of overloaded 'fun(int)' is ambiguous
note: candidate: int fun(int)
 extern "C" int fun(int);
                ^~~
note: candidate: int {anonymous}::fun(int) <deleted>
 inline namespace { int fun(int) = delete; }
                        ^~~
Run Code Online (Sandbox Code Playgroud)

例子.

  • 为什么需要内联匿名命名空间? (2认同)