StoneThrow StoneThrow - 3 months ago 22
C++ Question

Instance of Most Vexing Parse with std::string and char*

This is a follow-up to my previous question: C++ compile error constructing object with rvalue std::string from which I learned about the Most Vexing Parse.

I understand now the gist of the problem, however there's one leftover item of syntax I still don't quite understand, which I'd like to ask as a standalone question, since the discussions on the previous post were getting quite long.

Given this code:

#include <iostream>
#include <string>

class Foo
{
public:
Foo(double d)
: mD(d)
{
}

Foo(const std::string& str)
{
try
{
mD = std::stod(str);
}
catch (...)
{
throw;
}
}

Foo(const Foo& other)
: mD(other.mD)
{
}

virtual ~Foo() {}

protected:
double mD;
};

class Bar
{
public:
Bar(const Foo& a, const Foo& b)
: mA(a)
, mB(b)
{
}

virtual ~Bar() {}

protected:
Foo mA;
Foo mB;
};

int main(int argc, char* argv[])
{
if (argc < 3) { return 0; }

Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));

Bar wtf(a, b);
}


I understand, now, that the line
Foo a(std::string(argv[1]));
can be interpreted as either:

(1) Create a Foo named
a
with an anonymous
std::string
that is created with a
char*
. (My desired interpretation)

or

(2) A declaration (not definition) for a function named
a
that takes a
std::string*
.

From answers to the original question, I learned that functions could be declared within the scope of another function. That was new to me, but seems within reason, I can buy it.

What I can't wrap my head around, though, is the interpretation of
std::string(argv[1])
as a
std::string*
.

argv[1] is a char*, so I still don't see why the line isn't interpreted as an anonymous
std::string
being constructed with a
char*
. After all, I've used code analogous to the following hundreds of times without ever scrutinizing whether this would result in anything other than the construction of a
std::string
with its
char*
constructor:

#include <iostream>
int main()
{
char* pFoo[] = {"foo"};
std::string str(pFoo[0]);
std::cout << str << std::endl;
return 0;
}


I'm on the cusp of understanding the most vexing parse problem; if someone could further explain this last niggling part, that might help push me over the edge.

Thank you.

Answer
Foo a(std::string(argv[1]));

declares a function named a which returns Foo and has one parameter (named argv) of type std::string[1]. Since array function parameters are always replaced with pointer parameters, the actual type of the function parameter becomes std::string*.