まず、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
「long long」が 'unsigned long'の全範囲を包含する保証はないと私は信じています。それが他のサイズ仕様のようなものであるなら、唯一の要件は少なくとも "long"と同じくらい多くのビットで表現されることです。タイプのプロモーションは、プラットフォームに関係なく一様に動作するはずなので、オーバーロードの解決に関してはいくらかの予測可能性があります。 – jpm
'std :: common_type'は、三項演算子の戻り値の型を決定するための規則と一致します。その観点から見ると、3項演算子は2つの分岐のどちらよりも大きな型を返すことは明らかに間違っているようです。 –
@KevinBallard私は実際にそれが明らかに間違っているとは思わない。ブランチが異なる署名を返すときに、そのブランチのいずれかよりも大きい型を返すことは、バグフリーであることが保証されている唯一の方法のようです。 – David