C ++外部声明隔离

时间:2013-10-02 03:06:26

标签: c++ namespaces

请考虑以下事项:

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

void g() {
    N::f();
}

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

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

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

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

示例:假设我的库名为Lib1,我想在Lib1命名空间内声明所有内容。

// Lib1.hpp
namespace Lib1 {
    class Class1;
    void func1();
    // ...
}

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

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

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

#ifdef __cplusplus
}
#endif

在我的图书馆中,我可以引用Lib2中的实体而不必包含Lib2.h,如果出于某种原因需要这样做:

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

    inline void inlineX() {
        func2();
    }
}

同时,客户端代码可以自由地包含Lib1.hppLib2.h(考虑到它是C ++友好的)而不会发生冲突。

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

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

有没有办法以与Lib3相同的方式与Lib2相关联?也就是说:引用Lib3内的Lib1.hpp中的实体,但不包括Lib3.hpp,但仍然允许客户端代码同时包含Lib1.hppLib3.hpp并且没有麻烦?< / p>

如果在Lib1中声明:

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

namespace Lib1 {
    inline void inlineY() {
        Lib3::func3();
    }
}

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

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

1 个答案:

答案 0 :(得分:1)

这不仅仅是C ++中using指令的预期用法吗?

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

// Lib1.hpp
#include <Lib3.hpp>
namespace Lib1 {
    using Lib3::func3;
}