I'm working on a library which has several template classes, all interrelated to such an extent that they all have the same template parameters. In a sense, a given template parameter set describes an nearly-self-contained universe of classes, maybe with a one or two routes between these class universes.
In current C++, I have no real way of grouping such 'class universes' together, except in a rather ugly and manual way. Here's an example of some inter-related templated classes that might highlight my point:
template<size_t dimension>
using vector_t = std::array<double, dimension>;
template<typename weight_t, size_t outer_dimension, size_t inner_dimension>
class A{
protected:
weight_t weight;
public:
weight_t get_weight(
const vector_t<outer_dimension>& foo,
const vector_t<inner_dimension>& bar
) const;
};
template<typename weight_t, size_t outer_dimension, size_t inner_dimension>
class B{
protected:
std::vector<std::shared_ptr<A<weight_t, outer_dimension, inner_dimension>>> A_vector;
};
template<typename weight_t, size_t outer_dimension, size_t inner_dimension>
class C{
protected:
std::vector<std::shared_ptr<A<weight_t, outer_dimension, inner_dimension>>> A_vector;
std::vector<std::shared_ptr<B<weight_t, outer_dimension, inner_dimension>>> B_vector;
public:
typename std::enable_if<
(inner_dimension > 0),
C<weight_t, outer_dimension + 1, inner_dimension - 1>
>::type do_something() const;
};
This is usable - and, in the actual library I'm working on, the structure is ideal for what I want to use it for. It is, on the other hand, extremely ugly, and rather explicit for my liking.
If templated namespaces existed in the C++ standard, I could do something a little nicer:
template<size_t dimension>
using vector_t = std::array<double, dimension>;
template<typename weight_t, size_t outer_dimension, size_t inner_dimension>
namespace universe{
typedef vector_t<outer_dimension> outer_vector;
typedef vector_t<inner_dimension> inner_vector;
class A{
protected:
weight_t weight;
public:
weight_t get_weight(const outer_vector& foo, const inner_vector& bar) const;
};
class B{
protected:
std::vector<std::shared_ptr<A>> A_vector;
};
class C{
protected:
std::vector<std::shared_ptr<A>> A_vector;
std::vector<std::shared_ptr<B>> B_vector;
public:
typename std::enable_if<
(inner_dimension > 0),
universe<weight_t, outer_dimension + 1, inner_dimension - 1>::C
>::type do_something() const;
};
}
Of course, templated namespaces don't exist in the C++ standard. There are some really hacky approaches to get around this, e.g. "templating" a namespace. Solutions include:
- using typedefs to make the whole point of templating redundant
- wrapping typedefs in namespaces to make the point of redundant templating even more redundant.
- having a 'types' struct, which is more preferable than the above two but still ugly (IMO).
Obviously, such solutions are workarounds to the fundamental issue - that namespaces can't be templated. Is there a specific reason that this has not been adopted by the standard, or is it simply something that is yet to be proposed (in an effective manner)?
I can see a variety of other use cases - for example, there are many generic libraries out there with a lot of focus on a single typedef template parameter, which could benefit from one overall parameter.