まず第一に、std::common_type (そしてもちろん boost::type_traits::common_type) は三項演算子を使用して型の結果を取得します。この場合、関連する引用はCppReferenceから取得されます, 6b)
E2 と E3 は算術型または列挙型です。通常の算術変換が適用されて共通の型になり、その型が結果になります。
この情報を使用して、通常の算術変換の規則をc++ 標準、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;
}
しかし、現在の動作が問題であることはわかっており、いくつかの驚きを取り除く提案が存在します。
-ハンネス