在C 中超载Bitshift操作员

Overloading bitshift operator in c++

本文关键字:Bitshift 操作员 超载 中超      更新时间:2023-10-16

我想对arm_neon.h中的ARM系统定义的uint32x4_t超载Bitshift运算符。

struct uint32x4_t {
   uint32_t val[4];
};

这应该通过呼叫SIMD函数来完成,该功能期望值转移并立即发生恒定:

uint32x4_t simdShift(uint32x4_t, constant_immediate);

shift.h

#ifndef SHIFT_H
#define SHIFT_H
namespace A {
   namespace B {
      /*uint32x4_t simdLoad(uint32_t*) {
         ...
      }*/
      template<int N>
      uint32x4_t shiftRight(uint32x4_t vec) {
        return vshrq_n_u32(vec,N);
      }
   }
}
uint32x4_t operator>>(uint32x4_t const & vec, const int v) {
  return A::B::shiftRight<v>(vec);
}
#endif

main.cpp

#include "shift.h"
int main() {
   uint32_t* data = new uint32_t[4];
   data[0] = 1;
   data[1] = 2;
   data[2] = 3;
   data[3] = 4;
   uint32x4_t reg;// = simdLoad(data);
   reg = reg>>3;
   return 0;
}

此代码产生错误:

‘uint32x4_t运算符>>(const uint32x4_t&amp;,int)必须有一个参数 类或枚举类型的Uint32x4_t运算符>>(UINT32X4_T const&amp; vec,const int v){

是否有解决"本机"类型(例如uint32x4_t)的operator>>的解决方法?

编辑:我调整了建议的解决方法,但错误仍然保持不变:(

ermig答案的增量改进:

template<int N>
constexpr std::integral_constant<int, N> i_{};
template<int N>
uint32x4_t operator >>(uint32x4_t value, std::integral_constant<int, N>) noexcept {
    return _mm_slli_si128(value, N);
}
int main() {
    std::uint32_t data[4] = {1, 2, 3, 4};
    uint32x4_t reg;// = simdLoad(&data);
    reg = reg >> i_<3>;
}

n.b。我将operator>>放在全局名称空间中;如果您想将其放在其他名称空间中,则需要在使用之前将操作员带入范围。

" uint32x4_t是一种本地类型,由arm_neon.h提供。(来自另一个评论)。

您最初面临的问题是C 使用了所谓的参数依赖性查找。对于A::B::uint32x4,C 将考虑A::B::operator>>(uint32x4, int)。也就是说,C 将以各自参数的命名空间查看。

您的问题是uint32x4位于全局名称空间中,但您将operator>>放在另一个名称空间中。那完全是错的。将其放在正确的名称空间中。

请注意,名称空间是避免名称冲突的两种机制之一。超载是另一种机制。名称空间适用于所有类型的名称:变量,类型和功能。超载仅适用于功能。但是在这种情况下,这是足够的,因为操作员是功能的子集。您不会得到名字冲突;您的operator>>超载与其他operator>>

用于使用恒定立即的函数调用(通常在SIMD Intrinsics中相遇),我通常将模板函数与整数模板参数一起使用。以下示例使用SSE2,但对于霓虹灯,它会相似:

template<int shift> __m128i Shift(__m128i value)
{
    return _mm_slli_si128(value, shift);
}
int main()
{
    __m128i a = _mm_set1_epi8(3);
    __m128i b = Shift<2>(a);
    return 0;
}

不幸的是,我不知道如何为C 操作员制作它。当然,我们可以使用模板参数创建一个操作员,但是使用以下方式非常不便:

template<int shift> __m128i operator >> (__m128i value, int shift_)
{
    return _mm_slli_si128(value, shift);
}
int main()
{
    __m128i a = _mm_set1_epi8(3);
    __m128i b = operator >> <2>(a, 2);
    return 0;
}

@ildjarn启发的变体:

template<int N> struct Imm {};
#define IMM(N) Imm<N>()
template<int shift> __m128i operator >> (__m128i value, Imm<shift>)
{
    return _mm_slli_si128(value, shift);
}
int main()
{
    __m128i a = _mm_set1_epi8(3);
    __m128i b = a >> IMM(2);
    return 0;
}

一种解决方案是将operator>>A::B名称空间移动到全局名称空间。如果所有其他符号都是不同的命名空间,那么您只需要限定它们即可。例如,如果simdShiftA::B中,您仍然可以像这样具有全局operator>>

uint32x4_t operator>>(uint32x4_t const & vec, const int v) {
    return A::B::simdShift(vec, v);
}

,但我想使operator>>成为uint32x4_t的成员更合适:

struct uint32x4_t {
    uint32_t val[4];
    uint32x4_t operator>>(const int v) const;
};
namespace A { namespace B {
/// TODO: Put declaration/definition of simdShift here
}} // namespace A { namespace B {
uint32x4_t uint32x4_t::operator>>(const int v) const {
    return A::B::simdShift(*this, v);
}

或或者,正如Ildjarn在评论中所建议的那样,将A::B名称空间中的符号拉到您通过写作使用的上下文中:

using namespace A::B;