Reputation: 5856
I have a header-only C++ library with several namespaces.
For example one header file may contain
//header1.h
namespace library{
namespace componentA{
template<typename T>
class Someclass{};
}
}
And another one
//header2.h
namespace library{
namespace componentB{
template<typename T>
class SomeOtherClass{
void Foo(const componentA::Someclass<T>& reference);
void Bar(const componentA::Someclass<T>& reference);
};
}
}
Now while this works, having a header-only library it becomes tedious to write the namespace again and again, especially when you are having multiple classes and nested namespaces involved.
So I did this:
//new header2.h
namespace library{
namespace componentB{
using namespace componentA;
template<typename T>
class SomeOtherClass{
void Foo(const Someclass<T>& reference);
void Bar(const Someclass<T>& reference);
void FooBar(const Someclass<T>& reference);
void FooWithBar(const Someclass<T>& reference);
};
}
}
While this is certainly more convenient to type, it has the problem that now a client of the library can also use Someclass<T>
by using the componentB
namespace like this, which leads to an ambiguous interface and ultimately to inconsistent code.
For example a client now could use
componentB::Someclass<T>
even though it is originally defined in componentA
Is there a way to get the shorthand only available "privately"?
Upvotes: 2
Views: 1137
Reputation: 5856
I figured Out the solution myself after a while of thinking. Unfortunately this is not straightforward.
//header1.h
namespace lib_noexport{
namespace library{
namespace componentA{
template<typename T>
class Someclass{};
}
}
}
}
using namespace lib_noexport;
And then
//header2.h
namespace lib_noexport{
using library::componentA::Someclass;
namespace library{
namespace componentB{
template<typename T>
class SomeOtherClass{
void Foo(const Someclass<T>& reference){}
};
}
}
}
using namespace lib_noexport;
Now this yields the following:
library::componentB::SomeOtherClass<int> a; //works as expected
Someclass<int> b; //error
library::componentB::Someclass<int> c; //error
library::componentA::Someclass<int> b; //works
Still, the user could be stupid enough to use the undocumented lib_noexport:: but then i cannot help her any more..
Upvotes: 1
Reputation: 275896
namespace library {
namespace componentAImpl{
using ::library::componentB;
// ...
inline namespace exports{
struct foo{};
}
}
namespace componentA{
using namespace library::componentAImpl::exports;
}
}
users can access componentAImpl
, but should not.
Meanwhile, a clean set of symbols are exposed in library::componentA
.
Upvotes: 6
Reputation: 8718
Well, C++ 11? Using-declaration introduces a member of another namespace into current namespace or block scope.
namespace library{
namespace componentB{
using componentA::SomeOtherClass;
template<typename T>
SomeOtherClass{
void Foo(const Someclass<T>& reference);
void Bar(const Someclass<T>& reference);
void FooBar(const Someclass<T>& reference);
void FooWithBar(const Someclass<T>& reference);
};
}
}
Upvotes: 1
Reputation: 126552
If I understand your question correctly, then the answer is no. If typing/reading componentA::
before type names from the componentA
namespace is too much of a problem (honestly, that would be my preference), then you could use short namespace aliases:
namespace library { namespace componentB
{
// ...
namespace ca = componentA;
// ...
void foo(ca::SomeClass<T>);
// ...
} }
In any case, I discourage using directives in header files: they lead to name clashes and maintenance issues.
Upvotes: 3