user992113
user992113

Reputation: 175

decltype acting inconsistent when used in conjunction with conditional operator

While studying some of the new C++11 features, I observed some strangeness related to the new decltype keyword and its interaction with the conditional operator.

I was very surprised to see the output of the following program:

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

Which resulted in the surprising output:

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

I would have expected to have seen the following output (note the last line):

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

Does anyone know why this might be happening? I am using GNU g++.

Upvotes: 0

Views: 842

Answers (3)

CB Bailey
CB Bailey

Reputation: 791899

You need to change your expectation. The type of a conditional expression depends only on the types of it's operands, not the value of its operands.

There are a number of rules that are used to determine a common type for a conditional expression from the types of the second and third operands. The values of the second and third operands, even if they are constant expressions, are not taken into account.

You should consult the standard for the details of the rules for determining the common type. If a common type can't be found the program is usually ill-formed.

Upvotes: 8

Oscar Korz
Oscar Korz

Reputation: 2487

The resulting type of the conditional expression is the type of the last two arguments. The last two arguments need to be the same type. In your example, everything is being promoted to double to satisfy this requirement. If you add some type to your expression that cannot be implicitly coerced to double (for example, void*), there will be a compiler error.

Decltype is a red-herring in this scenario. This behavior is inherited from C.

Upvotes: 1

K-ballo
K-ballo

Reputation: 81349

The resulting type of the ternary expression is a common type to that of the last two arguments. In C++11 there is an std::common_type trait that would get that type (which if I remember correctly is actually implemented as decltype( false ? x : y )).

What you are getting in your last expression is a type common to bool, int, short, double, etc...

Upvotes: 3

Related Questions