In the code below, C's base class B1's template argument OFFSET depends on B0, and B2 on B1.
This is done by manual write the code every time an instance of C is created (in the main method). Is there a way to move this functionality to the definition of C instead?
template<int OFFSET>
struct A {
enum O { offset = OFFSET };
enum S { size = 2 };
};
template<int OFFSET>
struct B {
enum O { offset = OFFSET };
enum S { size = 4 };
};
template < typename B0, typename B1, typename B2 >
struct C : public B0, B1, B2 {
};
int main(int argc, const char *argv[])
{
// instance of C
C< A<1>,
B< A<1>::offset * A<1>::size >,
A<
B< A<1>::offset * A<1>::size >::offset *
B< A<1>::offset * A<1>::size >::size
>
> c1;
// does the same thing
C< A<1>,
B< A<1>::size >,
A<
A<1>::size *
B< A<1>::size >::size
>
> c2;
return 0;
}
EDIT:
To answer the comments, here are the steps I think needs to be taken to solve this:
Write a metafunction which can change the offset: set_new_offset which for T defines the type T<2>
Use boost::mpl::times to calculate the new offsets
Add more template magic...
You can do it with template templates in C, although I'm not 100% sold it's an improvement. If you only ever need three bases this should be fine. If you need an arbitrary number of bases...there must be a better way to do this than inheritance as this method will get unwieldy.
template<int OFFSET>
struct A {
enum O { offset = OFFSET };
enum S { size = 2 };
};
template<int OFFSET>
struct B {
enum O { offset = OFFSET };
enum S { size = 4 };
};
template < typename B0, template <int T> class B1, template <int T> class B2 >
struct C : public B0, B1<B0::offset * B0::size>, B2<B1<B0::offset * B0::size>::offset * B1<B0::offset * B0::size>::size> {
enum
{
B0_offset = B0::offset,
B1_offset = B1<B0::offset * B0::size>::offset,
B2_offset = B2<B1<B0::offset * B0::size>::offset * B1<B0::offset * B0::size>::size>::offset,
B0_size = B0::size,
B1_size = B1<B0::offset * B0::size>::size,
B2_size = B2<B1<B0::offset * B0::size>::offset * B1<B0::offset * B0::size>::size>::size
};
};
int main()
{
// instance of C
C< A<1>,
B,
A
> c1;
static_cast<void>(c1);
// does the same thing
C< A<1>,
B,
A
> c2;
static_cast<void>(c2);
std::cout << c1.B0_offset << std::endl;
std::cout << c1.B1_offset << std::endl;
std::cout << c1.B2_offset << std::endl;
std::cout << c1.B0_size << std::endl;
std::cout << c1.B1_size << std::endl;
std::cout << c1.B2_size << std::endl;
std::cout << c2.B0_offset << std::endl;
std::cout << c2.B1_offset << std::endl;
std::cout << c2.B2_offset << std::endl;
std::cout << c2.B0_size << std::endl;
std::cout << c2.B1_size << std::endl;
std::cout << c2.B2_size << std::endl;
return 0;
}