【问题标题】:Changing the template arguments of derived classes更改派生类的模板参数
【发布时间】:2012-01-06 17:03:05
【问题描述】:

在下面的代码中,C 的基类 B1 的模板参数 OFFSET 依赖于 B0,而 B2 依赖于 B1。

这是通过在每次创建 C 实例时手动编写代码来完成的(在 main 方法中)。有没有办法将此功能转移到 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;
}

编辑:

为了回答 cmets,我认为需要采取以下步骤来解决这个问题:

  • 编写一个可以改变偏移量的元函数: set_new_offset 为 T 定义类型 T

  • 使用 boost::mpl::times 计算新的偏移量

  • 添加更多模板魔法...

【问题讨论】:

  • 你想解决什么真正的问题?
  • @MarkB 说来话长,但部分真正的问题是在 C++ 中学习元编程。
  • 您似乎正在尝试以一种不寻常的方式解决问题。您从三个 structs 继承只是为了访问 3 个 OFFSET 和 3 个 SIZE 枚举。第二个和第三个可以根据第一个来计算。

标签: c++ generic-programming boost-mpl


【解决方案1】:

您可以使用 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;
}

【讨论】:

  • 我以前不知道模板模板参数,聪明的......在当前的实现中,我需要32个参数,所以我希望进一步改进......
  • @Allan 如果你需要 32 个模板参数,我 99% 确定你做的不是最理想的。
  • 我确定,但是我正在做的项目仍然没有切换到c++0x
  • 一些预处理器代码使它看起来还不错:#define B0_ B0&lt;1&gt;, #define B1_ B1&lt;B0_::offset * B0_::size&gt;, #define B2_ B2&lt;B1_::offset * B1_::size&gt;
【解决方案2】:

定义一个帮助类怎么样:

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 左右......)

【讨论】:

  • 很抱歉,我不明白您的解决方案。你注意到A和B不一样了吗? (大小 = 2 和大小 = 4)。您建议 C 的代码将来自 Composer,而不是来自 A 和 B?对于更复杂的 A 和 B 版本,这将如何工作? (以及 A 和 B 更不同的版本?)
  • @Allan:抱歉,尺寸确实有误。我认为它现在已修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2015-04-10
相关资源
最近更新 更多