2013-03-04 13 views
18

common_type<long, unsigned long>::typeunsigned longあるため、標準は言う不可欠昇進後のオペランドを...に関するなぜcommon_type <long、unsigned long> :: type = long longですか?

[...]符号なし整数型を持つオペランドがある場合は種類のランクに等しい以上 ランク他のオペランドの、 符号付き整数型を持つオペランドが 符号なし整数型でオペランドの型に変換されなければならない

不可欠な推進体制バギーを呼ぶが、それは大きな存在する場合のように思えるまでもありません符号付き整数型wh ichは、使用すべき符号付きオペランドと符号なしオペランドの両方の範囲を表すことができます。

私はいくつかのプラットフォームがlong == long longを持つ可能性があることを知っています。この場合、上記の規則が有効になります。しかし、であれば、より大きな符号付き整数型を使用できません。

+4

「long long」が 'unsigned long'の全範囲を包含する保証はないと私は信じています。それが他のサイズ仕様のようなものであるなら、唯一の要件は少なくとも "long"と同じくらい多くのビットで表現されることです。タイプのプロモーションは、プラットフォームに関係なく一様に動作するはずなので、オーバーロードの解決に関してはいくらかの予測可能性があります。 – jpm

+2

'std :: common_type'は、三項演算子の戻り値の型を決定するための規則と一致します。その観点から見ると、3項演算子は2つの分岐のどちらよりも大きな型を返すことは明らかに間違っているようです。 –

+0

@KevinBallard私は実際にそれが明らかに間違っているとは思わない。ブランチが異なる署名を返すときに、そのブランチのいずれかよりも大きい型を返すことは、バグフリーであることが保証されている唯一の方法のようです。 – David

答えて

6

まず、std :: common_type(もちろんboost :: type_traits :: common_type)は、3項演算子を使用して型の結果を取得します。この場合、該当する見積書は、E2及びE3は、算術または列挙型を持つ図6b)

CppReferenceから来ている:通常の算術変換は共通の型にそれらをもたらすために適用され、そのタイプは結果です。この情報我々はc++ standard、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; 
} 

をしかし、現在の行動が問題であることknownあり、そしてproposalは驚きの一部を削除するために存在している:ここでは試してみ素早く実行可能な例です。

-Hannes

+0

あなたの質問は何ですか?私は「なぜcommon_type :: type = long long?」と答えたのですか?あなたの例は私の例よりも多くの情報を追加しません、私が間違っていれば私を修正してください。しかしもちろん1 <* MaxULong * -1 ... –

+0

標準で実際にそれがそうであると言われていることは明らかです。私はそれがこの方法であることを再確認する必要はありませんでした。 。しかし、私が言ったように、私はあなたが下にあなたのリンクを持ってうれしいです、彼らは関連して部分的な答えです(それは既知の '問題'ですが、 – David

関連する問題