Изменение аргументов шаблона производных классов - PullRequest
1 голос
/ 06 января 2012

В приведенном ниже коде аргумент шаблона OFFSET базового класса B для C зависит от B0, а B2 - от B1.

Это делается путем ручной записи кода каждый раз, когда создается экземпляр C (в основном методе). Есть ли способ переместить эту функциональность в определение C вместо этого?

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:

Чтобы ответить на комментарии, вот шаги, которые, я думаю, необходимо предпринять, чтобы решить эту проблему:

  • Напишите метафункцию, которая может изменить смещение: set_new_offset, который для T определяет тип T <2>

  • Используйте boost :: mpl :: times для расчета новых смещений

  • Добавить еще шаблон магии ...

Ответы [ 2 ]

1 голос
/ 06 января 2012

Вы можете сделать это с шаблонами шаблонов в C, хотя я не продан на 100%, это улучшение. Если вам нужно всего лишь три базы, это будет хорошо. Если вам нужно произвольное количество баз ... должен быть лучший способ сделать это, чем наследование, так как этот метод станет громоздким.

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;
}
1 голос
/ 06 января 2012

Как насчет определения вспомогательного класса:

template <template <int> class C, int N>
struct Composer
{
    enum O { offset = C<N>::offset * C<N>::size; };
    enum S { size = C<N>::size; };
};

Тогда вы можете сказать:

C<A<1>, Composer<A, 1>, Composer<B, Composer<A, 1>::offset> c2;

При необходимости можно придумать композитора более высокого порядка, который позволит вам формировать более высокие «способности» композиции.

(возможно Composer следовало бы назвать Bind1st или около того ...)

...