The Scenario:
Let's say we have several libraries, each in their own namespace, each containing the exact same set of classes and functions with the same API in every namespace. These libraries have absolutely no knowledge of one another and share no common bases.
namespace A {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
namespace B {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
namespace C {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
I am in no way defending this design, but let's take it as a constraint that can't be changed. There are clearly better ways of doing this, but I'm not at liberty to change that right now.
The Problem:
Given the above, we often want implement higher level code that makes use of these libraries, but we don't want to have to repeat this code for each one. Templates seem like the obvious solution.
template<typename Foo, typename Bar, typename Baz>
class FooBarBazzer
{
std::unique_ptr<Foo> foo;
std::vector<Bar> bars;
Baz baz;
...
}
This doesn't look too bad, but it requires us to list Foo, Bar and Baz as template parameters and as the number of types involved has grown, this has quickly lead to some seriously unwieldy template argument lists.
I find myself wanting the following imaginary syntax:
template<namespace ns>
class FooBarBazzer
{
std::unique_ptr<ns::Foo> foo;
std::vector<ns::Bar> bars;
ns::Baz baz;
...
}
One potential workaround is to write and maintain a trait struct for each namespace containing a member type for every type in that namespace.
namespace A {
struct Types {
using Foo = A::Foo;
using Bar = A::Bar;
using Baz = A::Baz;
// A dozen more type aliases
};
}
namespace B {
struct Types {
using Foo = B::Foo;
using Bar = B::Bar;
using Baz = B::Baz;
// A dozen more type aliases
};
}
namespace C {
struct Types {
using Foo = C::Foo;
using Bar = C::Bar;
using Baz = C::Baz;
// A dozen more type aliases
};
}
template<typename Types>
class FooBarBazzer
{
std::unique_ptr<typename Types::Foo> foo;
std::vector<typename Types::Bar> bars;
typename Types::Baz baz;
...
}
But that seems like a lot of boilerplate. (It's also a lot of typename keywords sprinkled around, which isn't ideal, but I doubt that's avoidable.)
The Question:
Is there some better trick to accomplish this? To tell a template at instantiation time which namespace it should be looking for types in? One that doesn't require writing and maintaining much boilerplate?
I suspect the answer is no, but I'm constantly amazed by the things that experts are able to make the C++ type system do.