当与条件运算符一起使用时,decltype表示不一致

时间:2011-10-12 20:16:37

标签: c++ c++11 decltype

在研究一些新的C ++ 11特性时,我发现了一些与新的decltype关键字及其与条件运算符的交互相关的奇怪现象。

我很惊讶地看到以下程序的输出:

#include <iostream>
#include <map>

int main(void)
{
    // set up a map that associates the internal compiler-defined type_info name with a human readable name
    std::map <std::string, std::string> types;
    types[typeid(decltype(static_cast<unsigned char  >(0))).name()] = "unsigned char";
    types[typeid(decltype(static_cast<unsigned short >(0))).name()] = "unsigned short";
    types[typeid(decltype(static_cast<short          >(0))).name()] = "short";
    types[typeid(decltype(static_cast<unsigned int   >(0))).name()] = "unsigned int";
    types[typeid(decltype(static_cast<int            >(0))).name()] = "int";
    types[typeid(decltype(static_cast<float          >(0))).name()] = "float";
    types[typeid(decltype(static_cast<double         >(0))).name()] = "double";
    types[typeid(decltype(static_cast<bool           >(0))).name()] = "bool";

    std::cout << "Should be unsigned char : " << types[typeid(decltype(static_cast<unsigned char >(0))).name()] << std::endl;
    std::cout << "Should be unsigned short: " << types[typeid(decltype(static_cast<unsigned short>(0))).name()] << std::endl;
    std::cout << "Should be short         : " << types[typeid(decltype(static_cast<short         >(0))).name()] << std::endl;
    std::cout << "Should be unsigned int  : " << types[typeid(decltype(static_cast<unsigned int  >(0))).name()] << std::endl;
    std::cout << "Should be int           : " << types[typeid(decltype(static_cast<int           >(0))).name()] << std::endl;
    std::cout << "Should be float         : " << types[typeid(decltype(static_cast<float         >(0))).name()] << std::endl;
    std::cout << "Should be double        : " << types[typeid(decltype(static_cast<double        >(0))).name()] << std::endl;

    std::cout << "Expecting unsigned short: " << types[typeid(decltype(
        false ? static_cast<unsigned char  >(0) :
        true  ? static_cast<unsigned short >(0) :
        false ? static_cast<         short >(0) :
        false ? static_cast<unsigned int   >(0) :
        false ? static_cast<         int   >(0) :
        false ? static_cast<         float >(0) :
        false ? static_cast<         double>(0) :
                static_cast<         bool  >(0)
        )).name()] << std::endl;
}

这导致了惊人的输出:

Should be unsigned char : unsigned char
Should be unsigned short: unsigned short
Should be short         : short
Should be unsigned int  : unsigned int
Should be int           : int
Should be float         : float
Should be double        : double
Expecting unsigned short: double

我本来期望看到以下输出(注意最后一行):

Should be unsigned char : unsigned char
Should be unsigned short: unsigned short
Should be short         : short
Should be unsigned int  : unsigned int
Should be int           : int
Should be float         : float
Should be double        : double
Expecting unsigned short: unsigned short

有谁知道为什么会这样?我正在使用GNU g ++。

3 个答案:

答案 0 :(得分:8)

你需要改变你的期望。条件表达式的类型仅取决于它的操作数的类型,其操作数的值。

有许多规则用于根据第二个和第三个操作数的类型确定条件表达式的公共类型。第二个和第三个操作数的值,即使它们是常量表达式,也不予考虑。

您应该参考标准,了解确定常见类型的规则的详细信息。如果找不到常见的类型,程序通常是不正确的。

答案 1 :(得分:3)

三元表达式的结果类型是最后两个参数的常见类型。在C ++ 11中,有一个std::common_type特征可以获得该类型(如果我没记错的话实际上是decltype( false ? x : y )实现的)。

您在上一个表达式中获得的内容是boolintshortdouble等常见的类型...

答案 2 :(得分:1)

条件表达式的结果类型是最后两个参数的类型。最后两个参数需要是相同的类型。在您的示例中,所有内容都被提升为double以满足此要求。如果在表达式中添加一些无法隐式强制转换为double的类型(例如,void *),则会出现编译错误。

在这种情况下,Decltype是一个红鲱鱼。此行为继承自C。