C++外部声明隔离

ale*_*cov 9 c++ namespaces

考虑以下:

namespace N {
    extern "C" void f();
}

void g() {
    N::f();
}
Run Code Online (Sandbox Code Playgroud)

此代码在命名空间内声明了一个带有C链接的外部函数.这使得可以从私有名称空间引用这样的函数,从而避免由普通的全局外部声明引起的结果名称空间污染.它还允许客户端代码为相同的函数发出其他(希望兼容的)声明而不会发生冲突,即使在全局命名空间中也可能源自供应商提供的头部包含.

我经常依赖C和C++中的类似结构来将编译与一些库提供的错误编写或冲突的头文件隔离开来.(在C中,这是通过在函数范围发出所需的声明来实现的,这在C++中也是可能的,如果不是extern在函数范围内不允许链接声明的话.)这对于正确链接到明确的定义特别有用. ABI无需依赖供应商提供的头文件.

是否可以使用常规C++链接的函数或方法执行相同的操作?那就是:在私有命名空间(或任何类型的本地范围)内声明一个带有C++链接的外部函数,但是它可能是指在另一个命名空间内实际定义的函数?

预期功能(伪代码):

namespace N {
    // Actually should link with P::f() (and not N::f()).
    extern "C++" void f();
}

void g() {
    N::f(); // P::f();
}
Run Code Online (Sandbox Code Playgroud)

对于源文件(与头文件相对),这显然不是问题,因为在这种情况下命名空间污染无关紧要.因此,这个问题主要是指隔离库头文件中的声明(在模板和内联函数中使用).

欢迎编译器特定的解决方案(感兴趣的是MSVC和GCC).

示例:假设我的库被调用Lib1,我想在Lib1命名空间内声明所有内容.

// Lib1.hpp
namespace Lib1 {
    class Class1;
    void func1();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在假设我的库引用了另一个库,Lib2这是一个由其他人提供的C库.

/* Lib2.h */
#ifdef __cplusplus
extern "C" {
#endif

struct Struct2;
void func2();
/* ... */

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

在我的图书馆中,如果由于某种原因需要,我可以参考实体Lib2而不必包括在内Lib2.h:

// Lib1.hpp
namespace Lib1 {
    extern "C" void func2();

    inline void inlineX() {
        func2();
    }
}
Run Code Online (Sandbox Code Playgroud)

同时,客户端代码可以自由地包含两者Lib1.hpp并且Lib2.h(考虑到它是C++友好的)没有冲突.

现在,假设有第三个库,Lib3它是一个C++库并在Lib3命名空间中声明实体.

// Lib3.hpp
namespace Lib3 {
    class Class3;
    void func3();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

有没有办法以Lib3同样的方式联系Lib2?那就是:引用Lib3内部的实体Lib1.hpp,但不包括Lib3.hpp但仍然允许客户端代码同时包含Lib1.hpp并且Lib3.hpp没有麻烦?

如果,in Lib1,则声明:

// Lib1.hpp
namespace Lib3 {
    void func3();
}

namespace Lib1 {
    inline void inlineY() {
        Lib3::func3();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果客户端代码同时包含两者Lib1.hpp,那么可能会发生冲突Lib3.hpp- 当然不是在这个声明相同的简单示例中,但实际情况中的细微差别可能会在语法级别触发警告或错误,即使基础ABI相同,因为这违反了不在Lib1命名空间之外声明任何内容的前提.

希望这有助于理解这个问题.

Quu*_*one 1

这不正是该指令在 C++ 中的预期用法吗using

// Lib3.hpp
#pragma once
namespace Lib3 {
    void func3();
}

// Lib1.hpp
#include <Lib3.hpp>
namespace Lib1 {
    using Lib3::func3;
}
Run Code Online (Sandbox Code Playgroud)