9

The Linux <ncurses.h> header defines the function meta, and the C++ metaprogramming library meta puts all its code in the global namespace meta.

How can I use both in the same C++ program (not necessarily the same TU but that would be nice)? Is there a way to work around the name collision?

I can think of two brittle workarounds, but they are easy to break:

  • Workaround A:

     namespace linux {
     #include <ncurses.h>
     }  // namespace linux
     using linux::max_align_t;  // ncurses assumes it is in the global namespace
     #include <meta/meta.hpp>
    

    compiles but will probably fail to link since the ncurses symbols are expected in the global namespace.

  • Workaround B:

    #include <ncurses.h>
    namespace cpp {
    #include <meta/meta.hpp>
    }  // namespace cpp
    

    is very brittle since it will only work as long as the meta library doesn't assume that any of its symbols are in the global namespace. That is, if the library needs to disambiguate internally a symbol and uses ::meta::symbol_name for that, this approach will break.

gnzlbg
  • 7,135
  • 5
  • 53
  • 106
  • 1
    Approach A won't work, as you know yourself. Approach B might work - you can try. But I'd first try as hard as I can to see if I can separate those two libraries so that no single unit of transaltion uses both. – SergeyA May 23 '16 at 14:16
  • 3
    Try writing a wrapper for one so you never include both headers in the same translation unit and hope the linker is fine with it. – nwp May 23 '16 at 14:16
  • @NathanOliver `` has a function called meta, while `` has a namespace called `meta` within the global namespace, so the function name clashes with the namespace's name. – gnzlbg May 23 '16 at 14:17
  • 1
    Remember that namespace names is only a *compiler* thing. Once the object files has been generated there exists no "namespaces" any more. So translation-unit separation is definitely the way to go. It's probably a good design decision as well. – Some programmer dude May 23 '16 at 14:23
  • The `meta` library is one open source header right? How about just changing the namespace name? – Barry May 23 '16 at 14:25
  • 1
    @Barry That will work, if the library is a header-only library, or the OP is building the library from source. At least it will work until it's time to update the library. It might be some work getting all the search-replace right though. – Some programmer dude May 23 '16 at 14:26
  • @JoachimPileborg Just [two headers](https://github.com/ericniebler/meta/tree/master/include/meta) (if you exclude the tests). – Barry May 23 '16 at 14:32
  • @Someprogrammerdude Re: "only a compiler thing". I'm sure the namespace goes into the mangling, at least in Visual Studio. So the linker sees it, in a way. – Pablo H Mar 31 '20 at 18:31

2 Answers2

7

I would suggest workaround C: Isolate your code such that the meta library use and the ncurses use are in separate translation units in your project. This way in any particular translation unit there isn't one symbol being used as both a namespace and a global function.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    Since meta is a header only library it is probably easier to write a wrapper around `` that only includes this header in its cpp file. – gnzlbg May 23 '16 at 14:32
  • @gnzlbg If you look around a little I'm sure there already are C++ wrappers for the ncurses library that you can use. :) – Some programmer dude May 23 '16 at 14:34
  • 2
    @JoachimPileborg not needed: ncurses already includes c++ bindings (http://stackoverflow.com/questions/544280/c-wrappers-for-ncurses) – Garf365 May 23 '16 at 14:49
1

I'm reasonably certain that neither A nor B will actually work, at least as given. You've pointed toward one of them, but I think it's the less likely of the two. There are two problems that are basically mirror images of each other.

If the code in ncurses is declared as extern "C" (typical for many C libraries that have been made to work with C++), surrounding them with a namespace won't actually work--an extern "C" declaration basically ignores namespaces and declares a function in the global namespace. The namespace won't change much of anything, and you'll still have a collision.

If the content of <ncurses.h> is not declared extern "C", then you'll run into the problem you cited: the library is built with functions in the global namespace, but the client code is seeing definitions for code in the linux namespace. Since the namespace affects the mangled name (that's how it prevents a collision) your code won't be able to link. All the linux::* functions will show up as unresolved externals.

To make this work, you need to assure that none of the library code is declared extern "C", and specify the namespace inside the header (and the library source files), and re-compile the library with these declarations, so the library and its client code agree on the namespace where that code resides.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111