Search code examples
c++constructorcompiler-errorsmost-vexing-parse

Converting std::string to QString in constructor


I cannot understand why std::string converted into QString while passing it to constructor. Here is small example:

  class StringHandler
 {
 private:
     QString str;
 public:
     StringHandler(QString s): str(s) {}
  };

 int main(int argc, char *argv[])
 {
    QCoreApplication a(argc, argv);

    std::string str = "string";
    QString qstr(str); // it gives error there are no constructor QString(std::string)
    StringHandler handler(QString(str));//it does not give an error. Why?

    return a.exec();
 }

EDIT:

class StringHandler
{
public:
    StringHandler(QString s): str(s) {}
    QString str;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

std::string str = "string";
StringHandler handler(QString(str));//Here should be error, but there no error. Why?
qDebug()<<handler.str; //Error is here: request for member 'str' in 'handler', which is of non-class type 'StringHandler(QString)'

return a.exec();
}

Solution

  • Say hello to the most vexing parse.

    StringHandler handler(QString(str)); declares a function named handler that takes a QString and returns a StringHandler. Yes. Thanks to the C++ parsing rules.

    Now the error message request for member 'str' in 'handler', which is of non-class type 'StringHandler(QString)' makes sense: handler is being treated like a function of type StringHandler(QString) and you're trying to access a member named str in it, but of course functions have no members so the compilation fails.

    You can fix this by using the uniform initialization syntax:

    StringHandler handler{QString(str)};
    

    The above can't be parsed as a function declaration, and so the compilation should fail for the expected reason: no matching constructor QString(std::string).

    For more info, see C++'s most vexing parse again.