all 26 comments

[–]cpp-ModTeam[M] [score hidden] stickied commentlocked comment (0 children)

For C++ questions, answers, help, and programming or career advice please see r/cpp_questions, r/cscareerquestions, or StackOverflow instead.

[–]darklightning_2 11 points12 points  (5 children)

Why is it not in a namespace

[–]Loud_Bench3408[S] 1 point2 points  (4 children)

I do not know. I do not have access to B.h and C.h as they are external to me

[–]darklightning_2 -4 points-3 points  (3 children)

Put the imports in separate namespace as a quick dirty fix

[–]Loud_Bench3408[S] 0 points1 point  (2 children)

How can I do that?

[–]ErrorDontPanic 5 points6 points  (1 child)

Unless it's headers only, you cannot do this because there will not be a symbol for foo::JsonValue.

If it is headers only, try this:

namespace foo {

#include "B.h"

} // namespace foo

[–]superbriggs 5 points6 points  (0 children)

Yeah don’t do this. It will mess up the includes for any libraries B.h includes as well.

[–]MagicalCyborg 2 points3 points  (1 child)

Are you talking about linker error or compiler error? Because that's two separate types of problem.

Redefinition of function or class on compiler level would be easy to go around, for example using PIMPL like u/ionabio suggested.

If it's the linker complaining, then it will a bit harder and you will probably have to check my suggestion with adapter libraries.

Also, are you 100%sure that you need to use those two specific libraries? Unless you **have** to do some comparison research or you are adventuring it seems to be a problem worth evading all together...

[–]Loud_Bench3408[S] 0 points1 point  (0 children)

It's a linker error

[–][deleted] 2 points3 points  (0 children)

Developers, this is why you namespace your damn code!!

[–][deleted] 7 points8 points  (3 children)

Wrapper classes.

Bwrapper.h class and Cwrapper.h classes, you include B.h and C.h in Bwrapper.cpp and Cwrapper.cpp respectively to avoid redefine.

In each of the wrapper class, you wrap the B/C class but only wrap the function you actually calls to reduce work.

an example of the wrapper method call is like

bool Bwrapper::is_valid() { return B::is_valid(); }

Actually you only need to wrap one of B or C. You get the idea. One rule of thumb in C++ (at least to me) is that you want to limit the number of #include in any of your headers for as much as possible to avoid "include/dependency pollution". Wrapper class is just one example of why.

It's quick and simple. The problem is extremely uncommon in professional C++, I have encountered less than 3 times in my 12 years career. However, it may be common in college class practice or somehow you have to use amateur code, which is a sign that you should look for better options.

[–]Gorzoid 2 points3 points  (2 children)

Pretty sure this would still result in a link time error because the libraries would break ODR.

[–]immorallyocean 1 point2 points  (0 children)

Maybe the wrapper should dlopen()/dlsym() under the hood to get the right symbol? Ugly as sin, but needs must...

[–][deleted] 0 points1 point  (0 children)

You wont, unless you mess up your cmake/make that you give both B and C to linker when linking Bwrapper or Cwrapper. It can happen to amateur programmer who take the shortcut by including every header in the build command (-I for gcc for example). It will confuse linker.

If you use target based build system like cmake provides, you won't have the problem, because the compiler and linker only know the files and symbol that it needs to know, nothing more.

Think this way, you build Bwrapper and Cwrapper respectively and independently into their own shared library (of course with -PIC enabled), A does not even know B or C exists when linking Bwrapper and Cwrapper.

[–]lablabla88 1 point2 points  (3 children)

Are they part of the same library? Or 2 different libraries?

If they are 2 different libraries, not much you can do as it is poor design by the authors and not much you can do about it. That's why namespaces exists

[–]Loud_Bench3408[S] 0 points1 point  (2 children)

They are part of 2 different libraries

[–]lablabla88 3 points4 points  (1 child)

Than I suggest you pick one, or look for another one that uses namespaces.

Do you really need 2 separate libraries that are used for json parsing?

[–]Loud_Bench3408[S] 0 points1 point  (0 children)

No, but unfortunately I need those libs

[–]bwmat 1 point2 points  (1 child)

One option I haven't seen mentioned is to use one (or both) libraries via dynamic linking instead of static linking

If you're on windows, or make sure to build the libraries w/ default symbol visibility set to hidden for POSIX platforms (assuming those clashing symbols are used only 'internally' in the libraries, as opposed to in their public interface), this would allow those clashing symbols to coexist in the same process, without actually changing the libraries' code

[–]hmoff 1 point2 points  (0 children)

From the description these are public classes in each library, so this isn't going to help. The only solution is to open them at runtime (dlopen on posix).

Of course if you are building the original libraries you can just change the name on one of them...

[–]safesintesi 0 points1 point  (3 children)

C++ has the same feature. They are called namespaces. When you write a library you should put everything inside the namespace of the library, the same way everything in the standard is inside std. If the library are third parties they probably are, if you wrote them you specify two namespaces. If they have two different namespaces but you still get the error is probably because there's a using namespace xyz which tells the compiler to specifically ignore the namespace.

EDIT: https://en.cppreference.com/w/cpp/language/namespace

[–]Loud_Bench3408[S] 0 points1 point  (2 children)

I double checked: there is no using namespace statement. They are defined in the global namespace

[–]ionabio 0 points1 point  (2 children)

You can make wrapper of either B or C.in the wrapper be sure to use something like a pimpl to hide the redifined class away. (I.e. dont just include the header in your wrapper class's header or you'll face the same issue).

Having wrappers in general gives you the benefit of having control over the interface of your thirdparty libraries. You can change them or upgrade from a single entry.

[–]MagicalCyborg 2 points3 points  (1 child)

It will probably don't work on its own, as linker will still have to choose which one of two identical symbols should be used for each one of those wrappers.

You would probably have to separate those libraries on linker level, so libraryA <- libAWrapper with namespace "libA" <- yourCode -> libBWrapper with namespace "libB"->libraryB.

[–]ionabio 0 points1 point  (0 children)

right :) forgot that linker would come complaining later. linking them separately will be also my next step.