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

时间:2022-03-12 23:58:49

Let's say I have a function with "C" linkage in global scope.

假设我在全局范围内具有“C”链接的功能。

extern "C" int fun(int);

Then if I want to make it visible in a namespace I would do:

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

namespace foo {
   using ::fun;
}

But after this I am still able to call it as ::fun(0) in addition to foo::fun(0).

但在此之后我仍然可以将它称为:: fun(0)以及foo :: fun(0)。

So my question is, is there a way to disallow the call from the global namespace for function fun and only allow it to be called from namespace foo?

所以我的问题是,是否有一种方法可以禁止来自全局命名空间的调用以实现函数的乐趣,并且只允许从命名空间foo调用它?

4 个解决方案

#1


10  

Since the C language does not have namespaces, part of the extern "C" specifier indicates that the source name has no namespace.

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

Thus the following code would invoke the C function foo:

因此,以下代码将调用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
}

So you could just do

所以你可以做到

namespace bar
{
    extern "C"
    {
        #include "foo.h"
    }
}

or if you need to share it with the C code:

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

#ifdef __cplusplus
namespace bar
{
    extern "C"
    {
#endif
// .. C-compatible definitions etc
#ifdef __cplusplus
    }
}
#endif

#2


11  

The standard clearly establishes that the external C function is declared within a namespace, even if C doesn't know namespaces:

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

7.5/4: A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.

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

So instead of declaring the function in the global namespace, you could very well define it directly in your foo namespace:

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

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

You could then refer to this function only via the namespace:

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

foo::fun();  // yes !
::fun();     // doesn't compile !!!

Note that you could even declare the external C function in several namespaces. They would all refer to the same C function:

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

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

This is guaranteed by the standard :

这是由标准保证:

7.5/6: At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.

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

Note that if the extern function was declared in the global namespace in one compilation unit due to some specific constraints, you could still organize that this declaration is not seen in the other compilation units where you would use your local namespace. This is perfectly valid according to the standard statement above. However, some care would be needed if you play with different visibility in different compilation units !

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

#3


9  

You can do this since C++11 using a deleted declaration of an ambiguous function in an anonymous inline namespace:

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

inline namespace { int fun(int) = delete; }

Trying to call ::fun(0) or fun(0) will give an error:

试着调用:: 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; }
                        ^~~

Example.

#4


4  

You can't prevent any explicit intentional (mis)use here but you can hide it in a separate implementation file to make it hard to accidentally use:

你不能阻止任何明确的故意(误)使用,但你可以将它隐藏在一个单独的实现文件中,以使其难以意外使用:

In your header, declare the wrapper:

在标题中,声明包装器:

namespace foo
{
    int fun(int);
}

Then in a single private source file you wrap it up:

然后在一个私有源文件中将其包装起来:

extern "C" int fun(int);

namespace foo
{
    int fun(int v) { return ::fun(v); }
}

#1


10  

Since the C language does not have namespaces, part of the extern "C" specifier indicates that the source name has no namespace.

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

Thus the following code would invoke the C function foo:

因此,以下代码将调用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
}

So you could just do

所以你可以做到

namespace bar
{
    extern "C"
    {
        #include "foo.h"
    }
}

or if you need to share it with the C code:

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

#ifdef __cplusplus
namespace bar
{
    extern "C"
    {
#endif
// .. C-compatible definitions etc
#ifdef __cplusplus
    }
}
#endif

#2


11  

The standard clearly establishes that the external C function is declared within a namespace, even if C doesn't know namespaces:

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

7.5/4: A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.

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

So instead of declaring the function in the global namespace, you could very well define it directly in your foo namespace:

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

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

You could then refer to this function only via the namespace:

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

foo::fun();  // yes !
::fun();     // doesn't compile !!!

Note that you could even declare the external C function in several namespaces. They would all refer to the same C function:

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

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

This is guaranteed by the standard :

这是由标准保证:

7.5/6: At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.

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

Note that if the extern function was declared in the global namespace in one compilation unit due to some specific constraints, you could still organize that this declaration is not seen in the other compilation units where you would use your local namespace. This is perfectly valid according to the standard statement above. However, some care would be needed if you play with different visibility in different compilation units !

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

#3


9  

You can do this since C++11 using a deleted declaration of an ambiguous function in an anonymous inline namespace:

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

inline namespace { int fun(int) = delete; }

Trying to call ::fun(0) or fun(0) will give an error:

试着调用:: 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; }
                        ^~~

Example.

#4


4  

You can't prevent any explicit intentional (mis)use here but you can hide it in a separate implementation file to make it hard to accidentally use:

你不能阻止任何明确的故意(误)使用,但你可以将它隐藏在一个单独的实现文件中,以使其难以意外使用:

In your header, declare the wrapper:

在标题中,声明包装器:

namespace foo
{
    int fun(int);
}

Then in a single private source file you wrap it up:

然后在一个私有源文件中将其包装起来:

extern "C" int fun(int);

namespace foo
{
    int fun(int v) { return ::fun(v); }
}