(Why) Is this an example of a vexing parse? - c++

Is this an example of a vexing parse in C++?
#include <pthread.h>
#include <iostream>
class ScopeLock
{
public:
ScopeLock(pthread_mutex_t& m)
: mrMutex(m)
{
pthread_mutex_lock(&mrMutex);
}
~ScopeLock()
{
pthread_mutex_unlock(&mrMutex);
}
protected:
pthread_mutex_t& mrMutex;
};
class Foo
{
public:
Foo()
{
pthread_mutex_init(&m_, NULL);
}
~Foo()
{
pthread_mutex_destroy(&m_);
}
void Func()
{
ScopeLock(m_); // Is this a vexing parse?
std::cout << __FUNCTION__ << std::endl;
}
protected:
pthread_mutex_t m_;
};
int main(int argc, char* argv[])
{
Foo foo;
foo.Func();
return 0;
}
Output:
>g++ main.cpp
main.cpp: In member function \u2018void Foo::Func():
main.cpp:37:17: error: no matching function for call to 'ScopeLock::ScopeLock()'
ScopeLock(m_);
^
main.cpp:37:17: note: candidates are:
main.cpp:7:3: note: ScopeLock::ScopeLock(pthread_mutex_t&)
ScopeLock(pthread_mutex_t& m)
^
main.cpp:7:3: note: candidate expects 1 argument, 0 provided
main.cpp:4:7: note: ScopeLock::ScopeLock(const ScopeLock&)
class ScopeLock
^
main.cpp:4:7: note: candidate expects 1 argument, 0 provided
I think the compiler fails because it is trying to create a ScopeLock object (named m_) with no ctor arguments, and correctly identifies that the only ScopeLock ctor takes one pthread_mutex_t& as argument -- is that correct?
Why is this a vexing parse, though (if it is)? Why is line 37 not interpreted as creation of an anonymous ScopeLock object with ctor argument m_?
If the above is an example of a vexing parse, why is the below not a vexing parse?
#include <iostream>
#include <string>
class Foo
{
public:
Foo()
{
pStr = "Foo";
}
~Foo()
{
}
void Func()
{
const std::string& rStr = std::string(pStr);
std::cout << rStr << std::endl;
}
protected:
const char* pStr;
};
int main(int argc, char* argv[])
{
Foo foo;
foo.Func();
return 0;
}
Compilation and output:
>g++ main.cpp
>./a.out
Foo
>
The second code block seems very analogous to the first. Why, then does the compiler not treat line 18 as creation of a std::string named pStr with no ctor arguments? The cout of rStr resulting in "Foo" actually shows that an anonymous std::string was created with const char* argument.
I'd be grateful if anyone could shed light here. Thank you.
Update
I just noticed that in the first code block changing this:
ScopeLock(m_); // Is this a vexing parse?
to this:
const ScopeLock& rSl = ScopeLock(m_); // Is this a vexing parse?
results in compilation passing. So something about turning the anonymous object to an rvalue fixes the vexing parse problem? I'm unclear.
On the flip side, in the second code block, changing this:
const std::string& rStr = std::string(pStr);
to this:
std::string(pStr);
compiles just fine. However the resulting cout of pStr is empty. I think this confirms that the compiler is actually creating a std::string named pStr using the default constructor. So actually that is analogous to what it was trying to do in the first code block.
I'd still be grateful if someone could confirm if what I've surmised is correct.

The "canonical" meaning of the "most vexing parse" refers to the ambiguity between object declaration and function declaration.
What you have in your case is a different ambiguity: an ambiguity between object declaration and functional-style cast (more formally: functional notation of explicit type conversion, see 5.2.3). This latter ambiguity is resolved in favor of object declaration. Hence the error. Your code is seen by the compiler as a simple
ScopeLock m_;
which makes it to complain about missing default constructor.
6.8 Ambiguity resolution [stmt.ambig]
1 There is an ambiguity in the grammar involving expression-statements and declarations: An expression statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
Whether you want to call it another flavor of "most vexing parse" is up to you.
There are many different ways to make the compiler to interpret it as an expression instead of declaration. You can also do it as
0, ScopeLock(m_);
or as
(ScopeLock(m_));

Why is line 37 not interpreted as creation of an anonymous ScopeLock object with ctor argument m_?
It's because the Standard has a rule that if code has structure that can be interpreted as either a declaration or a function call, treatment as the declaration is chosen.
It doesn't worry about whether treatment as a declaration causes an error later.
If you think about it, having a fallback to an entirely different interpretation would cause some very nasty action-at-a-distance results during code maintenance. Imagine if you wrote this code and it was accepted as a function-style-cast, and later someone added a default constructor...

Try to replace
ScopeLock(m_); to ScopeLock s(m_);. The object needed its name.
-
Maybe compiler was seeing ScopeLock(m_) as ScopeLock m_. I compiled with clang, and it showed similar error message.
Following line compiles without any complaint :
void Func()
{
ScopeLock(m)(m_);
std::cout << __FUNCTION__ << std::endl;
}

Related

Why can function call operator on temporary objects sometimes be interpreted as a declaration that does not shadow a parameter?

My question is similar to this answered question, but with one big difference.
If I try to compile the following,
void test(string x){
int x = 5;
cout << x << endl;
}
I get the expected warning:
In function ‘void test(std::__cxx11::string)’:
error: declaration of ‘int x’ shadows a parameter
int x = 5;
^
Now to get to the meat of my question; if I have a type with a function call operator like the following:
struct foo{
string bar;
foo(const string& bar) : bar(bar) { }
void operator()(){
cout << "my bar is \"" << bar << '"' << endl;
}
};
I can create a temporary object and call its () operator with foo("this will print")(); or with foo{"this will also print"}();
If I try to do the following, I will get a compiler error which is expected and can be explained with the post I linked above.
void redeclaration_error(){
string x("lol");
foo(x)();
}
However, things get weird here:
void hmm1(string str){
foo(str)();
}
void hmm2(string str){
foo{str}();
}
While hmm2 will print out its argument when called, hmm1 will do absolutely nothing. This is expected, as hmm1's body does nothing more than declare str to be of type foo. However, in the scope of hmm1, str is already declared as type string from the function's parameter, so why does this not result in a compiler error like error: declaration of ‘foo str‘ shadows a parameter?
I understand that the compiler is interpreting foo(str)(); as a declaration, and that lines like foo(str).operator()(); and (foo(str))(); will be interpreted as creating a temporary foo object and calling their function call operator, but why it it okay to declare a variable with the same name as a parameter in this circumstance?
Here's and Ideone link where I was playing around with this.
A simpler program to produce the same issue (the extra parentheses are a red herring):
void f(int x)
{
void x();
}
This is incorrect because of C++17 [basic.scope.block]/2:
[...] A parameter name shall not be redeclared in the outermost block of the function
definition nor in the outermost block of any handler associated with a function-try-block.
If a compiler accepts this code then it is a compiler bug.

Invalid object after elision of copy operation? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is it an error to use an empty set of brackets to call a constructor with no arguments?
Most vexing parse: why doesn't A a(()); work?
This one gets me mad. Maybe its just too simple.
struct Foo
{
Foo() {}
Foo(const Foo& f) {}
void work() {}
};
int main()
{
Foo f( Foo() );
f.work();
}
GCC 4.6 gives me:
error: request for member ‘work’ in ‘f’, which is of non-class type ‘Foo(Foo (*)())’
After elision of the copy operation the effective code might look like:
int main()
{
Foo f;
f.work();
}
But why can't i call work() ??
Edit:
Yes, duplicate (see below). Didn't find the original post when search first because the source of the symptoms of this is located where i didn't expect that.
Because Foo f( Foo() ); is a function declaration.
I think you want: Foo f;
Or in case you want to copy-construct:
Foo f( (Foo()) );
f is effectively a function declaration within main function.
Try
Foo f((Foo())); // to make the definition of f explicit enough.
n3337 8.2
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 can also occur in the context
of a declaration. In that context, the choice is between a function
declaration with a redundant set of parentheses around a parameter
name and an object declaration with a function-style cast as the
initializer. Just as for the ambiguities mentioned in 6.8, the
resolution is to consider any construct that could possibly be a
declaration a declaration. [ Note: A declaration can be explicitly
disambiguated by a nonfunction-style cast, by an = to indicate
initialization or by removing the redundant parentheses around the
parameter name. — end note ] [ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a));
//function declaration
S x(int());
//function declaration
S y((int)a);
//object declaration
S z = int(a);
//object declaration
}
— end example ]
C++ parser interprets Foo f(Foo()); expression as the function declaration with the signature Foo(Foo(*)()), i.e. a function returning Foo and taking a function pointer to the function returning Foo. Adding explicit parenthesis around the argument like so Foo f((Foo())); will resolve the ambiguity. But consider actually just doing Foo f; which avoids redundant code.

Very weird behavior: Class with template constructor with only one argument

Recently I've bumped into a weird behavior when having a class with a template constructor that accepts only one argument. This class under certain circumstances fails to initialize at all.
#include <iostream>
struct Foo
{
template<typename T>
Foo(const T& x)
{
std::cout << "--" << x << std::endl;
}
};
int main(int, char**)
{
Foo f(std::string());
std::cout << "++" << f << std::endl;
return 0;
}
What I have is a Foo structure with the constructor you see. In main I create a new Foo instance with an empty std::string. The example compiles and the output is:
++1
WTF??? As you may have noticed there are three problems with the this. First of all the constructor was never called, secondly the f was printed as "1", thirdly there is no overloaded operator<< that prints the Foo using the cout and despite that the compiler never complained. This means that the f is not a type of Foo.
I change the example slightly:
int main(int, char**)
{
Foo f(std::string(""));
std::cout << "++" << f << std::endl;
return 0;
}
...and the compiler throws an error that there is no overloaded operator<< and that is normal.
int main(int, char**)
{
Foo f(std::string("Hello"));
return 0;
}
Now the output is:
--Hello
and that's normal again.
The problem is when having passing to Foo::Foo a an empty object whether it is std::string() or float() or any_type(). I've tested the example in GCC 4.4 and 4.6 and I find this behavior very unexpected.
What is your opinion? Is this a GCC bug or am I missing something here?
Foo f(std::string());
It does not create an instance of type Foo, as you seem to think.
Instead, this declares a function of name f, whose return type is Foo, and parameter type is a function type (which takes no argument and returns std::string).
It is same as:
Foo f(std::string (*)()); //same as yours
The only difference this and your function declaration is that in your case the parameter type is function type (which eventually decays into function pointer type anyway), and in my case, the parameter type is function pointer type (which doesn't need to decay into pointer type).
As for why it prints ++1 is because it invokes operator<< which takes void* as argument, and this function prints the address of the function.
Now if you want to declare an object, then you need to use extra parens as:
Foo f((std::string())); //notice the extra parens!
This declares an object, and calls the constructor : http://ideone.com/Px815
See also this topic:
Most vexing parse: why doesn't A a(()); work?
You're experiencing the infamous C++ Most vexing parse. In your first example
Foo f(std::string());
is parsed as a function declaration, so no constructor is called.

Why is my constructor with non const reference as argument allowed to be called with temporary objects?

I have a sample code below.
#include<iostream>
template<typename T>
class XYZ
{
private:
T & ref;
public:
XYZ(T & arg):ref(arg)
{
}
};
class temp
{
int x;
public:
temp():x(34)
{
}
};
template<typename T>
void fun(T & arg)
{
}
int main()
{
XYZ<temp> abc(temp());
fun(temp()); //This is a compilation error in gcc while the above code is perfectly valid.
}
In the above code even though XYZ constructor takes argument as non const reference, it compiles fine while the fun function fails to compile. Is this specific to g++ compiler or c++ standard has to say something about it?
Edit:
g++ -v gives this.
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
XYZ<temp> abc(temp());
It compiles, because it is NOT a variable declaration. I'm sure you think its a variable declaration when the fact is that its a function declaration. The name of the function is abc; the function returns an object of type XYZ<temp> and takes a single (unnamed) argument which in turn is a function returning type temp and taking no argument. See these topics for detail explanation:
The Most Vexing Parse (at InformIT)
Most vexing parse (at wikipedia)
And fun(temp()) doesn't compile, because temp() creates a temporary object and a temporary object cannot be bound to non-const reference.
So the fix is this : define your function template as:
template<typename T>
void fun(const T & arg) //note the `const`
{
}
No, the standard doesn't allow to pass a temporary to non const reference. (C++0X introduced rvalue reference to allow this in some controlled cases), see 8.5.3/5 (which is too long for me to cite, the meaningful part is otherwise, the reference shall be to a non-volatile const type, but you have to read the whole list of cases to know that they don't apply here).
And
XYZ<temp> abc(temp());
is simply yet another example of the most vexing parse.

Why this is not a vexing parse?

Basically this is a follow up of this question about most vexing parse. I can understand that this is due to the ambiguity between the function declaration and variable definition.
But in Comeau online, I just tired the following.
class T{
public:
T(int i){
}
int fun1(){
return 1;
}
};
int main()
{
T myT(10); // I thought it'd be a function declaration that takes an int and returns a type T
myT.fun1(); // and a compiler error out here.
}
But it compiles fine and there were no errors. I looked into the standard docs but couldn't come to a reasoning.
So, what am I missing here?
Because 10 is not a type. :)
This would be a Most Vexing Parse:
T myT(T());
// T() gets interpreted as function pointer argument to a function returning T();
// This is equivalent to:
T myT(T (*fn)());
Another variety of the Most Vexing Parse is this one:
unsigned char c = 42;
T myT(int(c));
// int(c) gets interpreted as an int argument called c.
// This is equivalent to:
T myT(int c);
The 10 cannot be a parameter type name, so this must be a variable declaration.
The compiler must choose a function declaration when it can do that, but in many cases like this it cannot and there is no ambiguity.
It's not a vexing parse because you used an integer literal rather than, say:
T myT(T());
As in this complete example:
#include <iostream>
struct T { int f() { return 1; } };
int main(int argc, char** argv) {
T t(T());
std::cout << t.f() << '\n';
return 0;
}
Which is ambiguous because it could mean:
myT is a T initialised with a default-constructed T; or
myT is a function returning a T and taking one argument of type T(), which denotes a zero-argument function whose return type is also T.
The latter interpretation is the default one, which is why a compiler error results from attempting to use the newly declared function as though it were the object you expected it to be.
See the Wikipedia article about it.