【问题标题】:Compile-time search in static-array静态数组中的编译时搜索
【发布时间】:2012-05-22 15:57:44
【问题描述】:

在一个项目中,我有几个类,其中封装了作为静态数组实现的矩阵,例如:

struct StaticContainer
{
    static const short e[2][4];
};

/// Initialize components of member-array (with external linkage).
const short StaticContainer::e[2][4] = {
    { -1,  0, 0, 1 },
    {  0, -1, 1, 0 }
};

我想实现一个提供反向映射的元函数,从 StaticContainer::e 中的列返回到第二个索引(在本例中为 1-4)。理想情况下,是这样的:

template< typename TContainer, short TeX, short TeY >
struct VectorToIndex
{
    enum { value = ??? };
};

最后,我想通过(如果这可能的话):

BOOST_STATIC_ASSERT( 0 == VectorToIndex< StaticContainer, -1, 0 >::value );

这可能吗?我最初尝试递归搜索'e'矩阵失败了,因为每当我尝试访问(在编译时)我得到的条目(GCC):

error: ‘StaticContainer::e’ cannot appear in a constant-expression

我应该明白矩阵中的值在编译时不可用吗?

我会很感激任何 cmets。我可以随意更改矩阵的初始化/存储方式(所以我在考虑一些编译时注册机制)。唯一的限制是在编译时获得这种反向映射。

说明:

  • e-matrix 中的每一列代表一个空间方向(在本例中为 2D)。这些列保证是不同的。

  • 我希望元函数的结果如下:

    VectorToIndex< StaticContainer, -1, 0 > --> '0' at compile-time
    VectorToIndex< StaticContainer,  0,-1 > --> '1' at compile-time
    VectorToIndex< StaticContainer,  0, 1 > --> '2' at compile-time
    VectorToIndex< StaticContainer,  1, 0 > --> '3' at compile-time
    

如果这个模板是用无效的数字组合实例化的(即它不是矩阵中的一列),我想产生一个编译错误。

  • 我目前拥有的解决方案是一个简单的程序,它手动编写带有必要模板实例的文件。这满足了要求(结果是正确的,并且对于无效向量存在编译时错误 - 因为缺少相应的模板实例化)。但是,由于我的代码库中有许多类似于“StaticContainer”的类(其中许多具有较大的矩阵),因此此过程会生成数千行代码:(。

【问题讨论】:

  • 你不能使用mpl?如果您可以将数组中的值定义为整数常量,那么您可以使用现有的boost::mpl::vector 可能吗?
  • 我会调查的。你知道是否可以在 boost::mpl::vector 中存储一个矩阵(如 std::vector<:vector>>?)
  • @Dragos:你能否更好地定义逆映射,如果我提供(0, 0) 作为参数呢? 12 都是有效的索引。
  • @MatthieuM.:感谢您的关注。我添加了一些说明。
  • 如果您可以访问实现此功能的编译器,也可以使用可变参数模板来解决此问题。当我今晚晚些时候回到家时,我会试着告诉你怎么做,也就是说,如果在那之前没有其他人这样做的话。从那里开始,如果需要符合 c++03 标准,通过 mpl 增强它应该不难,尽管我必须说我自己从未真正使用过 mpl。

标签: c++ metaprogramming template-meta-programming


【解决方案1】:

正如所承诺的,这里有一个解决方案。我没有使用可变参数模板重新发明整个元编程库,而是利用这个机会尝试了 boost mpl,结果证明它很有表现力。使用它,VectorToIndex 将如下所示:

template<typename basis, typename axis>
struct VectorToIndex : 
    boost::mpl::if_<
        boost::mpl::greater<boost::mpl::size<basis>, typename boost::mpl::find<basis, axis>::type::pos>,
        typename boost::mpl::find<basis, axis>::type::pos,
        boost::mpl::empty_base
    >::type
{
};

如果“轴”存在于“基础”中,则VectorToIndex&lt;basis, axis&gt;::value 等于其在[0,基础大小)范围内的索引。如果不是这样,则VectorToIndex&lt;basis, axis&gt;::value 未定义,因此访问它可能会产生编译时错误或 通过 SFINAE 选择性实例化。

要表示轴,应该使用 boost::mpl::vector,如下所示:

typedef boost::mpl::vector<boost::mpl::int_<1>, boost::mpl::int_<0>, boost::mpl::int_<0> > e1;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<1>, boost::mpl::int_<0> > e2;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<0>, boost::mpl::int_<1> > e3;

考虑到上面的定义,一个有

VectorToIndex<boost::mpl::vector<e1, e2, e3>, e1>::value -> 0
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e2>::value -> 1
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e3>::value -> 2
VectorToIndex<boost::mpl::vector<e1, e2>, e3>::value -> COMPILE-TIME ERROR

【讨论】:

  • 感谢您的解决方案! MPL 确实是一个了不起的库,也是我最终选择的路径(但忘了发布 - 真丢人)。
【解决方案2】:

您的声明不匹配:

  • typename TContainer 表示模板参数是一个类型
  • StaticContainer::e 是一个值

无法匹配。

我能想到一些潜在的解决方案,但第一个问题显然是:为什么不手动构建反向矩阵并使用assert 来证明其正确性?它当然更简单,简单就是美丽。

【讨论】:

  • 关于不匹配:我的意图是将容器作为 tparam 传递给“VectorToIndex”,因为我在实际代码中有许多类似于“StaticContainer”的类。这也是我寻找元编程解决方案的原因。目前,我有一个简单的程序,可以为这些反向映射生成(运行时)所有模板实例化,但输出量很大,而且它也使构建过程复杂化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
  • 2018-09-07
  • 2013-09-23
  • 1970-01-01
  • 2019-11-28
  • 1970-01-01
  • 2015-03-27
相关资源
最近更新 更多