In this example:
template<typename T>
struct ConditionalValue
{
typedef boost::optional<T> type;
};
template<typename T>
struct FindRootValueType
{
typedef typename T::root_type type;
};
template<typename T>
struct FindRootValueType<typename ConditionalValue<T>::type>
{
typedef typename ConditionalValue<T>::type type;
};
template<typename T>
struct Base
{
typedef T value_type;
typedef typename FindRootValueType<value_type>::type root_type;
std::vector<value_type> data;
};
template<typename T>
struct A : public Base<typename ConditionalValue<T>::type>
{
};
template<typename T>
struct B : public Base<A<T>>
{
};
template<typename T>
struct C : public Base<B<T>>
{
};
// C<int>::value_type == B<int>
// C<int>::data == std::vector<B<int>>
// C<int>::data ~= std::vector<std::vector<std::vector<boost::optional<int>>>>
// C<int>::root_type == boost::optional<int>
ConditionalValue
is a template alias that simply tries to give an alternate name to boost::optional
(such that something else can be used to replace it), and FindRootValueType
is a metafunction intended to walk up a chain of types that have definitions similar to those shown at the bottom until it stops at the boost::optional
, and then simply returns that.
However as written this does not work (at least not in VS2008). To fix it, the specialization of FindRootValueType must explicitly use boost::optional<T>
, not the typedef that should be equivalent to it. (And this defeats the goal of only specifying the underlying implementation type in one place.)
Is this a compiler bug or is this supposed to not work? Or am I just doing something wrong? Is there a better way to write it such that it works as expected?
I also tried reversing the logic thusly:
template<typename T>
struct FindRootValueType
{
typedef T type;
};
// define Base here
template<typename T>
struct FindRootValueType<Base<T>>
{
typedef typename T::root_type type;
};
// define A here
template<typename T>
struct FindRootValueType<A<T>>
{
typedef T type;
};
// define B, C here (no specialisation)
But this doesn't work either (I think because specialisation doesn't follow base types, or possibly it's just the order of definition). I don't want to have to specialise for B, C etc specifically.
(BTW, in both of the above, "not working" means that compiler errors were produced that indicated that it was using the base definition of FindRootValueType
, not the specialisation.)