Избавление от сдвига gcc с помощью отрицательного предупреждения - PullRequest
3 голосов
/ 06 ноября 2008

У меня есть код, который выглядит следующим образом:

template<unsigned int A, unsigned int B>
int foo() {
  int v = 1;
  const int x = A - B;
  if (x > 0) {
    v = v << x;
  }
  bar(v);
}

gcc будет жаловаться на то, что x является отрицательным для некоторых экземпляров A, B; Тем не менее, я выполняю проверку, чтобы убедиться, что она неотрицательна. Какой лучший способ обойти это? Я знаю, что могу привести x к значению unsigned int, но это приведет к предупреждению о том, что x больше ширины v (поскольку оно приводит отрицательное число к положительному) Я знаю, что есть обходной путь, который включает создание новой шаблонной функции shift, но я бы хотел этого избежать, если это возможно.

Ответы [ 3 ]

3 голосов
/ 06 ноября 2008

Поскольку A и B известны во время компиляции, вы можете не только избавиться от своего предупреждения, но вы также можете избавиться от времени выполнения if без каких-либо приведений, таких как:

#include <iostream>
using namespace std;

template< unsigned int A, unsigned int B >
struct my
{
    template< bool P >
    static void shift_if( int & );

    template<>
    static void shift_if< false >( int & ) {}

    template<>
    static void shift_if< true >( int & v ) { v <<= A - B; }

    static void op( int & v ) { shift_if< (A > B) >( v ); }
};

template< unsigned int A, unsigned int B >
int foo()
{
    int v = 1;
    my< A, B >::op( v );
    return v;
}

int main() {
    cout << foo< 1, 3 >() << endl;
    cout << foo< 3, 1 >() << endl;
    cout << foo< 300, 1 >() << endl;
    cout << foo< 25, 31 >() << endl;
    return 0;
}
2 голосов
/ 06 ноября 2008

почему бы не сделать x типом unsigned char и привести его? неужели вам не нужно сдвигать более 255 бит?

const unsigned char x = static_cast<unsigned char>(A - B);

или, возможно, используйте маскирование, чтобы гарантировать, что сдвиг будет в границах, подобных этому:

const unsigned int x = static_cast<unsigned int>(A - B) & 0x1f; // limit A-B to have a range of (0 - 31)

EDIT:

в ответ на комментарий вот идея:

template<unsigned int A, unsigned int B>
int foo() {
  int v = 1;
  const int x = A - B;
  if (x > 0) {
    v = v << (static_cast<unsigned int>(x) & 0x1f);
  }
  bar(v);
}

ПРИМЕЧАНИЕ: вы можете заменить 0x1f на что-то вроде: (CHAR_BIT * sizeof (T) - 1)

РЕДАКТИРОВАТЬ: в ответ на последний комментарий этот код не выдает никаких предупреждений, компилируя с: g ++ -W -Wall -ansi -pedantic test.cc -o test

#include <iostream>

template<unsigned int A, unsigned int B>
int foo() {
  int v = 1;
  const int x = A - B;
  if (x > 0) {
    v = v << (static_cast<unsigned int>(x) & 0x1f);
  }
  return v;
}

int main() {
    std::cout << foo<1, 3>() << std::endl;
    std::cout << foo<3, 1>() << std::endl;
    std::cout << foo<300, 1>() << std::endl;
    std::cout << foo<25, 31>() << std::endl;
}
0 голосов
/ 06 ноября 2008

Будет ли это работать?

const short unsigned int x = A - B;

Это отрезает намного больше битов, чем нужно, но если ваши значения A - B достаточно малы ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...