Почему не common_type <long, unsigned long>:: type = long long?

common_type<long, unsigned long>::type unsigned long, потому что в отношении операндов после целостной рекламы стандарт говорит...

[...], если операнд с целым типом без знака имеет ранг больше или равен равный рангам типа другого операнда, операнд с значный целочисленный тип преобразуется в тип операнда с unsigned integer type

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

Я знаю, что некоторые платформы могут иметь длинный длинный длинный длинный, и в этом случае это правило может вступить в силу. Но если имеется более крупный тип интегрального интеграла, не следует ли его использовать?

Ответы

Ответ 1

прежде всего, std:: common_type (и, конечно, boost:: type_traits:: common_type), используйте трёхмерный оператор для получения результата типа. В этом случае соответствующая цитата исходит из CppReference, 6b)

E2 и E3 имеют тип арифметики или перечисления: обычные арифметические преобразования применяются, чтобы привести их к общему типу, этот тип является результатом.

С помощью этой информации мы можем найти правила для обычных арифметических преобразований в стандарте С++, 5p10, стр. 88.

- В противном случае, если операнд с целым типом без знака имеет ранг, больший или равный рангам типа другого операнда, операнд со знаком целочисленного типа должен быть преобразован в тип операнда с целым числом без знака.

Итак, в основном ответ на ваш вопрос:... потому что стандарт говорит так.

Но вы не единственный, кто считает это поведение неожиданным. Вот пример быстрого запуска:

#include <iostream>
#include <typeinfo>
#include <type_traits>

int main(int argc, const char* argv[])
{

    std::cout << typeid(std::common_type<char, unsigned char>::type).name() << std::endl;
    // I would expect "short", and the result is "int", ok so far.

    std::cout << typeid(std::common_type<short, unsigned short>::type).name() << std::endl;
    // I would expect "int", and the result is "int", yay.

    std::cout << typeid(std::common_type<int, unsigned int>::type).name() << std::endl;
    // I would expect "long", but the result is "unsigned int"

    std::cout << typeid(std::common_type<long, unsigned long>::type).name() << std::endl;
    // I would expect "long long", but the result is "unsigned long"


    // So this usual arithmetic conversion can lead to unexpected behavior:
    auto var_auto = true ? var_i : var_ui;
    std::cout << typeid(var_auto).name() << std::endl;   // unsigned int
    std::cout << var_auto << std::endl;                  // 4294967173

    return 0;
}

Но проблема в том, что текущее поведение является проблемой и существует , чтобы удалить некоторые из сюрпризы.

-Hannes