静态数组中的编译时搜索

Compile-time search in static-array

本文关键字:搜索 编译 数组 静态      更新时间:2023-10-16

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

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

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

如有任何评论,我将不胜感激。我可以自由更改矩阵的初始化/存储方式(所以我在考虑一些编译时注册机制(。唯一的约束是在编译时获取此反向映射。

澄清:

  • 电子矩阵中的每一列代表一个空间方向(在本例中为 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"的类(其中许多具有更大的矩阵(,因此此过程:(生成数千行代码。

正如所承诺的那样,这里有一个解决方案。我没有使用可变参数模板重新发明整个元编程库,而是利用这个机会尝试了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<basis, axis>::value等于其在范围 [0, 基数大小] 中的索引。否则,这不是真的,则VectorToIndex<basis, axis>::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

您的声明不匹配:

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

它无法匹配。

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