Оптимизация шаблонов C++

В какой момент / может ли часть о методе шаблона быть оптимизирована компилятором? Будет ли это удалить недоступный код, развернуть ненужные циклы? (Биты используют неподписанные int- блоки, Integer использует неподписанные длинные)

Плюс, есть ли тип данных C++, означающий "я целое число размера ваших реестров процессоров"?

template<size_t bits> class IntegerFactoryImpl : public IntegerFactory<Integer<bits>>{
private:
    template<int sizeOfLong, int sizeOfInt> Integer<bits> getOne(const Bits& b) const{

        Integer<bits> integer = this->getOne();
        size_t roof = (b.blocks() > integer.size()*(sizeOfLong/sizeOfInt))? integer.size()*(sizeOfLong/sizeOfInt) : b.blocks();
        for(size_t i = 0; i < roof; ++i){
            integer.at(i/(sizeOfLong/sizeOfInt)) = 0;
            for(size_t j = 0; j < (sizeOfLong/sizeOfInt); ++j){
                if(i % (sizeOfLong/sizeOfInt) == j){
                    integer.at(i/(sizeOfLong/sizeOfInt)) |= ((unsigned long)b.block(b.blocks()-i-1)) << (sizeOfInt*j);
                    break;
                }
            }
        }
        for(size_t i = roof; i < integer.size()*(sizeOfLong/sizeOfInt); ++i){
            if(i % (sizeOfLong/sizeOfInt) == 0){
                integer.at(i/(sizeOfLong/sizeOfInt)) = 0;
            }
        }
        return integer;
    }

public:

    virtual ~IntegerFactoryImpl() throw(){}

    virtual Integer<bits> getOne() const{
        return Integer<bits>();
    }

    virtual Integer<bits> getOne(const Bits& b) const{
        return this->getOne<sizeof(unsigned long)*8, sizeof(unsigned int)*8>(b);
    }
};

Будет ли разница с этим кодом (без использования шаблона):

template<size_t bits> class IntegerFactoryImpl : public IntegerFactory<Integer<bits>>{

public:

    virtual ~IntegerFactoryImpl() throw(){}

    virtual Integer<bits> getOne() const{
        return Integer<bits>();
    }

    virtual Integer<bits> getOne(const Bits& b) const{

        Integer<bits> integer = this->getOne();
        size_t roof = (b.blocks() > integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)))? integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)) : b.blocks();
        for(size_t i = 0; i < roof; ++i){
            integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) = 0;
            for(size_t j = 0; j < ((sizeof(unsigned long)/sizeof(unsigned int)); ++j){
                if(i % ((sizeof(unsigned long)/sizeof(unsigned int)) == j){
                    integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) |= ((unsigned long)b.block(b.blocks()-i-1)) << ((sizeof(unsigned int)*8)*j);
                    break;
                }
            }
        }
        for(size_t i = roof; i < integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)); ++i){
            if(i % ((sizeof(unsigned long)/sizeof(unsigned int)) == 0){
                integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) = 0;
            }
        }
        return integer;
    }
};

(редактировать: я только что обнаружил, что код не работает должным образом (я исправил это), но оригинальный вопрос все еще применяется..)

1 ответ

Решение

Правильно, компилятор оптимизирует все, что он может вычислить во время компиляции, и если у вас есть цикл, который повторяется только один раз (например, for(i = 0; i < 1; i++), это удалит петлю полностью.

Что касается целых размеров, это действительно зависит от того, что вы пытаетесь достичь, если лучше использовать long или же int, Например, в x86-64 64-битная операция займет дополнительный байт, чтобы указать, что следующая инструкция является 64-битной, а не 32-битной. Если компилятор сделал int Длиной 64 бита код становился (немного) больше и, следовательно, не очень хорошо подходил бы для кешей и т. Д. И т. Д. Нет преимущества в скорости между 16-, 32- или 64-битными операциями [для 99% операции, умножение и деление являются некоторыми из очевидных исключений - чем больше число, тем больше времени требуется, чтобы разделить или умножить его ((На самом деле, количество битов SET в числе влияет на время умножения, и я считаю, что деление тоже)) ] в x86-64. Конечно, если вы, например, используете значения для выполнения операций битовой маски и тому подобное, используйте long предоставит вам 64-битные операции, для выполнения которых требуется вдвое меньше операций. Это явно преимущество. Так что это "правильно" использовать long в этом случае, даже если он добавляет дополнительный байт на инструкцию.

Также имейте в виду, что очень часто, int используется для "меньших чисел", поэтому для многих вещей дополнительный размер int будет просто потрачен впустую, и займет дополнительное место в кэше данных и т. д., и т. д. int остается 32-разрядным также для сохранения размера больших целочисленных массивов и тому подобного на разумном размере.

Другие вопросы по тегам