2017-02-22 77 views
1

我想重載在arm_neon.h的ARM系統上定義的uint32x4_t的bitshift運算符。在C++中重載bitshift運算符

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中:

struct uint32x4_t { 
    uint32_t val[4]; 
}; 

這應該與一個SIMD函數的調用,它期望的價值轉移和恆定立即完成

#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; 
} 

This code produ CES錯誤:

‘uint32x4_t operator>>(const uint32x4_t&, int)’ must have an argument of class or enumerated type uint32x4_t operator>>(uint32x4_t const & vec, const int v) {

有一種解決方法重載operator>>爲「本地」類型,如uint32x4_t

編輯:我適應了建議的解決方法,但錯誤依然保持不變:(

+0

您需要將操作員納入範圍; '使用名稱空間A :: B;'是一個簡單的修復。另外,'simdShift'所期望的'constant_immediate'必須是_constant表達式_;一個'const int v'參數是不夠的。 – ildjarn

+0

@ildjarn但我不能將constexpr傳遞給一個函數,我可以嗎? – Hymir

+2

@Hymir:不是'int',沒有。但是,您可以將其設置爲函數模板,並傳遞'std :: integral_constant '的實例,它將起作用。您可以使用變量模板或UDL來構造清晰的整型實例。 – ildjarn

回答

3

上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>; 
} 

Nb我已將operator>>放入全局命名空間中;如果你想把它放在不同的命名空間中,你需要在使用它之前將操作符帶入作用域。

1

一個解決辦法是到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; 
+0

看起來很棒,但uint32x4_t是由arm_neon.h提供的本機類型。因此,我不能簡單地將操作員>>添加爲成員,我可以嗎? – Hymir

+0

@Hymir不是會員,沒有。但是,您可以爲現有類型全局定義運算符。如果你想將它作爲一個成員,你必須首先將'uint32x4_t'封裝在你自己的類型中,然後將操作符添加到該類型中。 –

+0

@RemyLebeau如果我使用這樣的: 命名空間A {namspace B { 模板 uint32x4_t shiftRight(uint32x4_t VEC){ 返回vshrq_n_u32(VEC,N); } } } uint32x4_t操作者>>(uint32x4_t常量&VEC,const int的體積){ 返回A :: B :: shiftRight (VEC); } 並像這樣使用它: uint32x4_t vec >> 3; 我得到了同樣的錯誤: 「uint32x4_t operator >>(const uint32x4_t&,int)'必須有類或枚舉類型的參數 uint32x4_t operator >>(uint32x4_t const&vec,const int v){」 – Hymir

2

「uint32x4_t是土生土長的鍵入,由arm_neon.h提供。「(來自其他評論)。

您最初面臨的問題是C++使用了一種稱爲參數相關查找的方法。對於A::B::uint32x4,C++會考慮A::B::operator>>(uint32x4, int)。也就是說,C++將查找各自參數的命名空間。

您的問題是uint32x4是在全局命名空間,但你把你的operator>>在另一個命名空間。這是錯誤的。把它放在正確的命名空間中。

請注意,名稱空間是爲避免名稱衝突而提供的兩種機制之一。重載是另一種機制。名稱空間適用於所有類型的名稱:變量,類型和函數。超載僅適用於功能。但在這種情況下,這就足夠了,因爲運算符是函數的一個子集。你不會得到名字衝突;您的operator>>過載與其他operator>>

2

對於調用具有常量立即數的函數(它通常在SIMD內在函數中遇到)我通常使用具有整型模板參數的模板函數。下面的例子是使用SSE2但NEON這將是類似的:

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; 
} 
+0

這就是我實現它的方式!但我認爲操作員>>閱讀起來會更好。 – Hymir