2013-03-04 49 views
18

common_type<long, unsigned long>::typeunsigned long çünkü standart diyor ayrılmaz promosyon sonra işlenen ... ilgilendirenNeden common_type <uzun, imzasız uzun> :: tip = uzun uzun değil?

[...] işaretsiz tamsayı türü olan işlenen varsa tip rütbesine eşit veya daha büyük rütbe diğer terimin, işaretli tamsayı türüyle işlenen işaretsiz tamsayı türü ile işlenen tipine dönüştürülür edilecektir

ayrılmaz terfi sistemi arabası diyorlar, ama daha büyük bir varsa gibi görünüyor değil imzalı tamsayı türü wh ich, kullanılması gereken hem imzalı hem de imzasız işlenenlerin aralığını temsil edebilir.

Bazı platformların uzun == uzunluğunda olabileceğini biliyorum; bu durumda yukarıdaki kurallar geçerli olabilir. Ancak ise daha büyük imzalı bir integral türü mevcut ise kullanılmamalıdır?

+4

Uzun long' imzasız long' 'tüm aralığı kapsayacak' herhangi garantisi yoktur inanmıyorum. Boyut özelliklerinin geri kalanı gibi olsaydı, tek gereksinim, en az "long" gibi çok sayıda bitle temsil edilmesidir. Tip tanıtım, platformdan bağımsız olarak düzgün bir şekilde davranmalıdır, bu nedenle aşırı yüklenme çözünürlüğü açısından bazı öngörülebilirlik söz konusudur. – jpm

+2

'std :: common_type', üçlü operatörün dönüş türünü belirleme kuralları ile eşleşir. Bu ışıkta bakıldığında, üçüncül operatörün iki kolundan birinden daha büyük bir tip döndüreceği açıkça yanlış görünüyor. –

+0

@KevinBallard Aslında bunun yanlış olduğunu düşünmüyorum.Şubeler farklı imzalı dönerse şubelerinden daha büyük bir döneme dönersek, hatasız olması garanti edilen tek şey gibi görünmektedir. – David

cevap

6

her şeyden önce, std :: common_type (ve elbette boost :: type_traits :: common_type) tür sonucunu almak için üçlü operatörü kullanır. Bu tip sonucudur, olağan aritmetik dönüşümler ortak tip getirmek için uygulanır: Bu durumda, ilgili alıntı 6b)

E2 ve E3 aritmetik veya numaralandırma türü var, CppReference geliyor. Bu bilgi biz c++ standard, 5p10 içinde zamanki aritmetik dönüşümleri için kuralları bulabilirsiniz ile

, sayfa 88.

- Aksi takdirde, işaretsiz tamsayı türü olan işlenen varsa büyük rütbe diğer işlenenin türünün sıralamasına eşit veya daha büyük, imzalanmış tamsayı türüne sahip işlenen, işlenmemiş tamsayı türüyle işlenenin türüne dönüştürülür.

Yani temelde sorunun cevabı: ... standart öyle diyor çünkü.

Ancak bu davranışı beklenmedik bulmayan tek kişi siz değilsiniz.

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

Ama şimdiki davranış bir sorun olduğunu known ve bir proposal sürprizler bazılarını kaldırmak için var: Burada denemek için hızlı çalıştırılabilir bir örnek.

-Hannes

+0

Peki o zaman sorunuz nedir? "Neden common_type değil :: type = long long?" Örneğiniz benim örneğimden daha fazla bilgi eklemiyor, yanılıyorsam beni düzeltin. Ama tabi ki, 1 <* MaxULong * -1 ... –

+0

Bu standartta, standardın olduğu gibi olduğunu açıkça belirttim, bu şekilde olduğunu teyit eden bir cevaba gerek duymadım * çünkü standart şöyle diyor: . Ama dediğim gibi, alt kısımdaki bağlantılarınız olduğuna sevindim, alakalı ve kısmi bir cevap var (ki bu bilinen bir 'problem', ama bunun neden bu şekilde başladığını göstermiyor) – David