将std::array的一些元素强制转换为较短的std::array

Cast some elements of std::array to shorter std::array

本文关键字:array std 转换 元素      更新时间:2023-10-16

是否可以强制转换std::array<double, 4>std::array<double, 3>

例如:

void f(std::array<double,3> &);
...
int main() {
    std::array<double,4> a;
    ...
    f(/* pass a[1], a[2] and a[3] */);
}

编辑:

上下文:有几个晶格自旋(点)特性是由不同的函数(不同的f()-s)计算的。这些函数应该填充数组的不同部分。(数组不能是结构化的,因为数字元素取决于编译时参数。)这些f()-s被调用了数百万次。

在保持功能不变的同时,没有比更简单的方法了

std::array<double, 3> temp{a[1], a[2], a[3]};
f(temp);

相反,让您的函数使用两个迭代器,使其工作的范围远不止一个包含3个元素的std::array

template<typename Iter>
void f(Iter first, Iter last);
f(std::next(std::begin(a)), std::end(a));

这里有一个不使用迭代器的编译时解决方案,因为你似乎认为它们会增加开销:

template<size_t N> void f(double*);
...
int main() {
    std::array<double,4> a;
    ...
    f<3>(a.data());
}

IMHO,这并不比只传递两个迭代器更好。如果f可以内联,编译器将能够优化从a.begin()a.begin()+3的遍历,以及如果您将其传递给array<double, 3>(如果您注意的话,您会注意到常数3在所有情况下都是常数。)

您可以尝试这个替代方案。因此,您的函数将接受您想要的任何数组。应在.h文件中定义

template<typename Type> void f(Type &arr)
{
 for (auto it=arr.rbegin(),int i=0;it!=arr.rend();++it,i++)
  {
    if (i < N)//<-- Your last N elements of arr
     std::cout << (*it) << std::endl;
  }
}

呼叫方式如下:

int main()
{
 std::array<double,3> test1;
 f(test1);
}

注意:您没有指定如何获得最后一个N元素。但是有几种方法。

由于std::array是标准布局类型(当然,只要内部类型是),而且布局与普通的旧数组兼容,下面的强制转换应该可以满足您的需要。

f(reinterpret_cast<std::array<double,3>&>(a));

现在,这个演员阵容非常丑陋,所以需要一些语法糖:

template<size_t N2, typename T, size_t N1>
std::array<T, N2> resize_array(std::array<T,N1> &a, int offset)
{
    return reinterpret_cast<std::array<T,N2>&>(a[offset]);
}
...
f(resize_array<3>(a, 1));

如果偏移量是编译器常量,您可以将其作为模板参数,甚至可以让编译器检查范围!但这是留给读者的练习。

您可以尝试联合:

int main() {
    union U {
        std::array<double,4> a;
        struct {
            double dummy;
            std::array<double,3> a;
        } s;
    } u;
    std::array<double,4> &a = u.a;
    std::array<double,3> &a1 = u.s.a;
    ...
    f(a1);
}

它应该可以工作,但我不完全确定它的便携性。。。