简体   繁体   中英

Strange constructor behavior

I am using Visual Studio 2013, and this is what I'm trying to figure out:

#include <iostream>
#include <vector>
using namespace std;

class A
{
public:
    int x = 1;
    bool y = true;

    A(int _x, bool _y) : x(_x), y(_y)
    {
        cout << "Constructor #1" << endl;
    }

    A(std::initializer_list<int> init_list)
    {
        cout << "Constructor #2" << endl;
    }
};


int main(int argc, char** argv)
{
    A Aobj1(10, false);
    A Aobj2(20, "false");
    A Aobj3{30, false};
    A Aobj4{40, "false"};

    return 0;
}

The output is:

 Constructor #1 Constructor #1 Constructor #2 Constructor #1 
  • The first call to constructor #1 is fine

  • Now the second construction of Aobj2(int, string) calling constructor #1 is strange. How is the compiler calling the (int, bool) constructor with a string argument? The "false" bool is not even converted to an int.

  • Aobj3 is also OK. Although the initializer_list is of type int, the compiler calls this because of brace-initialization and converts the bool to an int.

  • This one again baffles me. I would have expected this to be an error because a string cannot be converted to an int (as it was with the bool), and also expected the compiler to be calling the initializer_list constructor because it is a braced initialization. But the compiler chooses the (int, bool) constructor.

What is some background on the logic of the compiler?

Now the second construction of Aobj2(int, string) calling constructor #1 is strange. How is the compiler calling the (int, bool) constructor with a string argument?

More precisely, "false" is of type const char[6] and could decay to const char* , ie a pointer, and then could implicitly convert to bool .

A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool .

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false . All other values become true .

For the 4th case, the parameter std::initializer_list<int> can't match the argument 40, "false" , because there're no implicit conversion converting pointer to int . Then the constructor taking int, bool is selected, because "false" could be converted to bool implicitly as the above explained.

"false" is a const char[6] which decays to const char* and pointers are implicitly convertible to bool . That's why the compiler can call your constructor taking a int and a bool , since the compiler is allowed to perform one implicit conversion to make a function argument match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM