While looking at some C++03 code, I found an instance of the most vexing parse that confused me:
#include <sstream>
#include <string>
int main(int, char** argv)
{
std::stringstream ss(std::string(argv[0]));
}
live example on wandbox
In the snippet above, ss
is a declaration to a function that takes a std::string*
and returns std::stringstream
.
How is std::string(argv[0])
being parsed as std::string*
?
Intuitively I thought that argv[0]
was unambiguously an access to argv
.
The reason is because in the context of a function declaration, the compiler will interpret std::string(argv[0])
as std::string argv[0]
, i.e. a declaration of a zero-sized array as the function parameter named argv
(overshadowing the argv
from main
, as this is a different scope), which then is equivalent to a pointer by array-to-pointer-decay.
Therefore, std::stringstream ss(std::string(argv[0]));
means the same as std::stringstream ss(std::string* argv);
Edit: As it got correctly annotaded in the comments, zero-sized array declarations are invalid in C++, rendering the program ill-formed. When compiling this code with -pedantic
flags (GCC and clang), warnings will be issued. Visual Studio even produces a compilation error. For any other array index than 0, the argumentation above however still holds.
I believe this follows from the "declaration syntax is like expression syntax" principle, and the fact that "array" parameters are pointers.
The following array declarations are equivalent:
int x[1];
int (x)[1];
int (x[1]);
more or less because x[a]
, (x)[a]
, and (x[a])
are equivalent expressions.
Thus,
std::stringstream ss(std::string(argv[0]))
<=>
std::stringstream ss(std::string argv[0])
<=>
std::stringstream ss(std::string* argv)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With