An elegant way to express a left or right shift in a pattern

I currently have a template function that, depending on the template parameters A and B, can shift the value left or right:

template <int A, int B> void f(X) { // ... if (A >= B) { SetValue(X << (AB)); } else // (A < B) { SetValue(X >> (BA)); } 

When I create a template for A<B , I get a warning about a negative shift to the right on the first (unreachable) branch, and also I get a warning about a negative shift to the left in the first branch. Our code base does not contain warnings, so this is unacceptable. Is there a brief, readable alternative to these two shift operators?

Similar questions (for example, Dynamic left or right shift ) do not have this false warning, since the shift distance is a run-time variable.

+4
source share
11 answers

With C ++ 11 or boost.

 template<int A, int B> void f_impl(typename std::enable_if<(A >= B)>::type* = 0) { // first case } template<int A, int B> void f_impl(typename std::enable_if<(A < B)>::type* = 0) { // second case } template<int A, int B> void f() { f_impl<A, B>(); } 
+5
source

Pass the result (AB) and (BA) to unsigned.

+3
source

The most obvious is the transition to a function that performs an additional argument:

 template <bool Cond> struct Discrim {}; template <int A, int B> void f( Discrim<false> ) { SetValue( X, (A - B) ); } template <int A, int B> void f( Discrim<true> ) { SetValue( X, (B - A) ); } template <int A, int B> void f() { f( Discrim< (A < B) >() ); } 

(Using such a Discrim class template is one easy metaprogramming.)

+3
source

This is what I use in my drawing engine, which uses bits a lot to represent my board

 namespace detail { enum { Left, Right }; template<typename, std::size_t> struct Shift; // partial specialization for bitwise shift-left template<std::size_t N> struct Shift<Left, N> { template<typename T> T operator()(T x) const { return x << N; } }; // partial specialization for bitwise shift-right template<std::size_t N> struct Shift<Right, N> { template<typename T> T operator()(T x) const { return x >> N; } }; } // namespace detail template<int N> struct Shift { template<typename T> T operator()(T x) { return N >= 0 ? detail::Shift<Left, N>()(x) : detail::Shift<Right, -N>()(x); } }; template <int A, int B> void f(int x) { SetValue(Shift<AB>()(x)); } 

You can do something similar for ShiftAssign ( <<= and >>= ).

+1
source

Commenting davmac ("use & 0x1F") was the correct idea, except for the estimated maximum shift width. This has been easily fixed:

 template <int A, int B> void f(X) { // ... if (A >= B) { SetValue(X << abs(AB)); } else // (A < B) { SetValue(X >> abs(BA)); } 
+1
source

You can add a new template and configure it accordingly, for example:

 template<bool b> int Shift(int i, int a, int b); template<true> int Shift(int i, int a, int b) { return i << (ab); } template<false> int Shift(int i, int a, int b) { return i >> (ba); } 

And then call it as Shift<(A >= B)>(X, A, B) . That should work.

0
source

Above my head:

 template <int A, int B> struct whatever { static void f() { SetValue(X << (A - B)); } }; template <int A, int B, bool reversed> helper : whatever<A, B> { }; template <int A, int B, true> : helper whatever<B, A> { }; template <int A, int B> do_it : helper<A, B, B < A> { }; template <int A, int B> void f() { return do_it<A, B>::f(); } 
0
source

You can put shift operations in separate structures and use std::conditional in C ++ 11:

 template <typename A, typename B, typename X> struct ShiftRight { static void shift() { SetValue(X >> (A - B)); } }; template <typename A, typename B, typename X> struct ShiftLeft { static void shift() { SetValue(X << (A - B)); } }; template <typename A, typename B, typename X> void f() { typedef typename std::conditional<A >= B, ShiftLeft<A, B, X>, ShiftRight<A, B, X>>::type ShiftType; ShiftType::shift(); } 
0
source
 template< int A, int B > void f(X) { std::function< int(int, int) > shift = A < B ? [](int X, int N) { return X << N; } : [](int X, int N) { return X >> N; } SetValue( shift( X, std::max(A,B) - std::min(A,B) ) ); } 
0
source

I think a rather minor change would simply be to nullify the incomplete shift with multiplication. The compiler can still do all the work at compile time:

 template <int A, int B> void f(X) { // ... if (A >= B) { SetValue(X << ((A < B) * (AB))); } else // (A < B) { SetValue(X >> ((A >= B) * (BA))); } 

I believe that a cleaner approach would be to send to a real / false specialized template that knows how to change the right direction.

0
source

How about something like this: -

 #include <iostream> template <int A, int B, bool D> class shift { }; template <int A, int B> class shift<A, B, false> { public: static int result(int x) {return x << (BA);} }; template <int A, int B> class shift<A, B, true> { public: static int result(int x) {return x >> (AB);} }; template <int A, int B> int f(int x) { return shift<A, B, (A>B)>::result(x); } int main() { std::cout << f<1, 2>(10) << "\n"; std::cout << f<2, 1>(10) << "\n"; } 
0
source

All Articles