2017-02-22 43 views
1

にARMシステムで定義されているuint32x4_tのビットシフト演算子をオーバーロードしたいとします。C++のビットシフト演算子のオーバーロード

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

このコードは、 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) {

uint32x4_tのような「ネイティブ」タイプのためoperator>>をオーバーロードするための回避策はありますか?

編集:私は提案の回避策を適応しますが、エラーがまだ同じ:(

+0

オペレータを有効範囲にする必要があります。 'using namespace A :: B;'は簡単に修正できます。とにかく、 'simdShift'が期待する' constant_immediate'は_式でなければなりません。 'const int v'パラメータでは不十分です。 – ildjarn

+0

@ildjarnしかし、関数にconstexprを渡すことはできませんか? – Hymir

+2

@Hymir: 'int'ではなく、いいえ。しかし、それを関数テンプレートにして、代わりに 'std :: integral_constant 'のインスタンスを渡すことができます。変数テンプレートまたはUDLを使用して、constructorのintegral_constantインスタンスを読みやすくすることができます。 – 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

一つの解決策は、グローバル名前空間にA::B名前空間からoperator>>を動かすことであろう他のすべてのシンボルが異なる名前空間であれば残っています。そして、あなたはちょうどそれらを修飾する必要が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 VEC){ 戻りvshrq_n_u32(VEC、N)uint32x4_t テンプレート。 }}} uint32x4_tオペレータ>>(uint32x4_tのCONST&VEC、のconst int型V){ 戻りA :: B ::右シフト(VEC)。 } このように使用してください: uint32x4_t vec >> 3; 同じエラーが発生しました: "uint32x4_t演算子>>(const uint32x4_t&、int) 'はクラスまたは列挙型の引数を持たなければなりません uint32x4_t演算子>>(uint32x4_t const&vec、const int v){" – Hymir

2

「uint32x4_tがネイティブでありますarm_neon.hによって提供されます。 "(別のコメントから)。

最初に直面している問題は、C++ではArgument-Dependent Lookupというものが使用されていることです。 A::B::uint32x4については、C++はA::B::operator>>(uint32x4, int)と考えています。つまり、C++はそれぞれの引数の名前空間を調べます。

uint32x4はグローバル名前空間にありますが、operator>>は別の名前空間に置かれています。それは間違っている。それを正しい名前空間に入れてください。

名前空間は名前の競合を避けるために提供される2つのメカニズムの1つです。オーバーロードは他のメカニズムです。名前空間は、すべてのタイプの名前(変数、型、関数)で機能します。オーバーロードは関数に対してのみ機能します。しかし、この場合、それは十分です。演算子は関数のサブセットです。あなたは名前の衝突を取得しません。あなたの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

関連する問題