Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ External Declaration Isolation

Tags:

c++

namespaces

Consider the following:

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

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

This code declares an external function with C linkage inside a namespace. This makes possible to refer to such a function from a private namespace, avoiding the resulting namespace pollution caused by an ordinary global external declaration. It also allows client code to issue other (hopefully compatible) declarations for the same function without conflicts, even in the global namespace, possibly originated from a vendor-provided header inclusion.

I often rely on similar constructs in both C and C++ to isolate compilations from bad-written or conflicting header files provided with some libraries. (In C, this is achieved by issuing the needed declarations at function scope, which would be also possible in C++, if not for the extern linkage declaration being not allowed at function scope.) This is specially useful for properly linking against a well-defined ABI without having to rely on vendor-provided header files.

Is it possible to do the same with functions or methods with regular C++ linkage? That is: to declare an external function with C++ linkage inside a private namespace (or at any sort of local scope), but which possibly refers to a function actually defined inside another namespace?

Intended functionality (pseudo-code):

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

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

This obviously is not a problem for source files (as opposed to header files), because namespace pollution does not matter in that case. Thus, this question refers mostly to isolating declarations in library header files (for use inside templates and inline functions).

Compiler-specific solutions are welcome (MSVC and GCC being of interest).

Example: suppose my library is called Lib1 and I want to declare everything inside the Lib1 namespace.

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

Now suppose my library refers to another library, Lib2, which is a C library provided by someone else.

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

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

#ifdef __cplusplus
}
#endif

In my library, I can refer to entities from Lib2 without having to include Lib2.h at all, if for some reason this is needed:

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

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

At the same time, a client code is free to include both Lib1.hpp and Lib2.h (considering it is C++-friendly) without conflicts.

Now, suppose there is a third library, Lib3, which is a C++ library and declares entities in the Lib3 namespace.

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

Is there a way to relate to Lib3 in the same manner as Lib2? That is: refer to entities in Lib3 inside Lib1.hpp, without including Lib3.hpp but still allowing client code to include both Lib1.hpp and Lib3.hpp with no hassles?

If, in Lib1, it is declared:

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

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

then it might occur conflicts if client code includes both Lib1.hpp and Lib3.hpp -- certainly not in this simple example in which the declarations are identical, but subtle differences in real situations can trigger warnings or errors at syntax level, even if the underlying ABI is the same, since this violates the premise of not declaring anything outside the Lib1 namespace.

Hope this helps to understand the question.

like image 557
alecov Avatar asked Oct 02 '13 03:10

alecov


1 Answers

Isn't this just the intended usage of the using directive in C++?

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

// Lib1.hpp
#include <Lib3.hpp>
namespace Lib1 {
    using Lib3::func3;
}
like image 161
Quuxplusone Avatar answered Oct 26 '22 23:10

Quuxplusone