Pass temporary object with standard constructor - c++

I'd like to pass a temporary object(std::string for example) to the constructor of my object:
class MyClass{
public:
MyClass(string a):
a(a)
{
}
string a;
};
int main(int argc, char *argv[]){
MyClass a(string());
cout<<a.a<<endl;
return 0;
}
But I receive this error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:28:11: error: request for member ‘a’ in ‘a’, which is of non-class type ‘MyClass(std::string (*)()) {aka MyClass(std::basic_string<char> (*)())}’
Everything works ok if I pass anything to the constructor of temporary object(for example string("")). Why?

This is an instance of what has been dubbed C++'s most vexing parse. The compiler interprets
MyClass a(string());
as the prototype of a function named a returning a MyClass and taking an unnamed string as a parameter.
You can disambiguate it by putting parenthesis around the call to strings constructor:
MyClass a((string()));
Or, as long as MyClass has an accessible copy constructor:
MyClass a = string();
Update for C++11
You can also disambiguate with the universal initialisation syntax, as long as your class doesn't have a constructor that takes an initializer_list:
MyClass a { string() };

As it has already been pointed out by Seth, that is a problem with the language and how the expression is parsed. Basically when the compiler finds the expression MyClass a(string()) it interprets it as the declaration of a function a that has the signature MyClass (std::string (*)()) (The extra (*) comes from an implicit conversion from function to pointer to function in arguments).
There are different approaches to overcome that syntax in your particular case:
MyClass a(""); // 1
MyClass b = std::string(); // 2
MyClass c(( std::string() )); // 3
The first approach is not to use the T() expression to create the rvalue, but rather a constant literal that will produce the same output. The shortcoming of this approach is that in this particular case you can use a literal, but the same solution cannot be applied to other types (i.e. if you had your own type that only had a default constructor)
The second approach is avoiding direct initialization, as the alternative syntax cannot be parsed as a function declaration. The problem with this approach is that while the result in your particular case is the same, it requires the constructor not to be explicit. (I.e. it would fail if your constructor was declared explicit MyClass( std::string const & )), but it is none
The third approach is adding an extra set of parenthesis around the first argument to the constructor (note that the same problem in parsing would happen with MyClass a(std::string(), std::string())). The problem with this approach (opinion) is that it is ugly, but it is otherwise the most flexible of the three.

Related

What happens internally as and when the second statement in this code is executed?

In the following C++ code, I am creating a class and declaring a private variable in that class.
#include <iostream>
class num{
int k;
public:
operator int(){
return k;
}
};
int main(){
num obj;
std::cout<<obj; // calls int()
return 0;
}
On execution, this code will print the value of 'k' in 'obj' of type num. That clearly indicates that the member function of the class num has been invoked somehow. The invoked member function has the header 'operator int()', so, how does this function get invoked since I have not operated on obj and just printed it's value ?
The compiler looks for a valid overload of
operator<<(std::ostream&, something);
Since
operator<<(std::ostream&, num const&);
is not defined/provided, it looks for any allowed alternatives. Since num allows implicit type conversion to int, this is used, creating code equivalent to
std::cout<<static_cast<int>(num);
In fact, this is the exact reason for providing such an type-conversion operator: the type (num in this case) can be used instead of the conversion type in (almost) any function call w/o the need for explicit type conversion.
The code
operator int(){
return k;
}
is a conversion of a num object to an int object. The conversion is implicit which means that it can be done automatically, i.e. even when you don't ask for it. In other words - if the compiler needs an int object but has a num object, the compiler will automatically call int() to convert num to an int.
Therefore you can do strange things like:
int n = 10 + obj;
and
void foo(int x)
{
....
}
foo(obj);
This goes even further... If the compiler needs a << but num doesn't provide one, the compiler sees that it can convert num to int and that int has a <<. Consequently the compiler decides to do that.
A personal opnion:
It might seem smart to be able to convert some type to another type automatically. However, it is also confusing - especially to your co-workers. Therefore I'll recommend to avoid implicit conversions. If you need a conversion make it explicity. Then there will be no nasty surprises.

Weird parse in C++: int f(int(arg)) equivalent to int f(int arg) - can anyone explain it?

This was discovered by one of my coworkers when trying to construct an object with a single argument like this:
char testString[] = "test string";
...
MyClass instance(QString(testString));
They were aware of the situation where if you construct in the function-style idiom with a single argument it will be parsed as a forward-declared function, e.g.
char test[] = "hello";
MyClass instance1(0, test) //constructs an object
MyClass instance2(test) //invalidly forward-declares a function
but they were stumped by what they thought should work as it contained a function-style cast, or single-argument constructor invocation, inside the brackets.
I have since figured out that their constructor call was getting parsed like:
MyClass instance(QString testString);
Instead of passing in the variable testString to the cast operator, it declares a function with a parameter of the same name. My question is, why does it do that? It seems to be allowing the name of the parameter to be surrounded by brackets.
This was discovered by one of my coworkers
No, it was "discovered" decades ago and is an extremely famous quirk of the language.
https://en.wikipedia.org/wiki/Most_vexing_parse
My question is, why does it do that? It seems to be allowing the name of the parameter to be surrounded by brackets.
It is. The C declaration syntax is not so prescriptive as to disallow this specific case. In the general case, it's useful for more complex constructions like this:
void foo(int (*func)(char));
// (takes a pointer to a function returning int and taking char, bool)
// as opposed to:
void foo(int *func(char));
// (takes a function returning int* and taking char)
// as this is literally equivalent to the clearer:
void foo(int* func(char));
and, in C++:
void foo(int (&array)[5]) {}
// (takes a reference to an array of five integers)
// as opposed to:
void foo(int &array[5]) {}
// (takes an array of five `int&`s ... and fails to compile accordingly)
Here is the admittedly unwieldy solution for your specific case:
MyClass instance((QString(testString)));
// ^ ^
or, more helpfully since C++11:
MyClass instance(QString{testString});
// ^ ^
This was in fact one of the driving factors behind introducing uniform initialisation syntax.
Addendum
if you construct in the function-style idiom with a single argument it will be parsed as a forward-declared function, e.g.
MyClass instance2("hello") //invalidly forward-declares a function
This claim is simply untrue.
Also, char *testString = "test string"; has been deprecated for 17 years and illegal for 4.
In C++, and in C, declarators may be surrounded by any number of parentheses:
int a;
int (b);
int ((c));
int f(int (x));
This is mainly useful to differentiate function pointer declarators from declarators of functions that return pointer types. For example, here f is a pointer to a function that takes an int and returns an int:
int (*f)(int x);
In other words, (*f)(x) is an int if x is an int. Whereas here, f is a function that takes an int and returns a pointer to an int:
int *f(int x);
In other words, *f(x) is an int if x is an int.

cast to string operator overloading in C++

I am working on a class that has a method with the following signature:
operator const std::string & () const
It's documented as "cast to string operator".
I am wondering how to effectively invoke it. Unfortunately the following expression:
std::string(foo)
produces this error:
some_test.cpp:13:41: error: no matching function for call to'
std::basic_string<char>::basic_string(Foo (&)(std::string))'
Considering that foo is of type Foo, declared and instantiated as Foo foo(std::string(filename))
being a begginner of C++, this leaves me a bit confused. Any hints on what this means?
foo is of type Foo, declared and instantiated as Foo foo(std::string(filename))
That's a function declaration, interpreting filename as the name of a function parameter, equivalent to
Foo foo(std::string filename);
A variable declaration would look like
Foo foo(filename);
or, if you needed an explicit conversion (which you probably don't here)
Foo foo{std::string(filename)}; // C++11 or later
Foo foo = Foo(std::string(filename)); // historic dialects
If you question was about the usage of operator const std::string & () const, it is quite simple : this operator is used when you need to convert to a std::string. Example :
Foo foo(filename);
std::string s = foo; // uses the declared operator const std::string & () const

return type of std::bind implicitly convertible to two different explicit constructors

Given two explicit constructor overloads (based on different std::function<...> types), the return value of std::bind is able to select either (thereby making the call ambiguous)
call of overloaded ‘Bar(std::_Bind_helper<false, void (Foo::*)(int),
Foo*, int>::type)’ is ambiguous
If I comment out either, then the code compiles!
I would have thought making the constructors explicit would have either selected the correct overload, or prevented both from being selected?
Of course explicitly creating a std::function at the point I bind works:
Bar b(std::function<void(int)>(std::bind((&Foo::process), &f, 1)));
However, I'm puzzled as to why type deduction doesn't work?
If the return value from std::bind matches neither of the two constructor signatures, the fact they are explicit should prevent both from being selected.
If the return value from std::bind matches one of the two constructor signatures, the fact they are explicit should cause the correct one to be selected.
What is actually happening here?
Full working code below:
#include <functional>
struct Foo
{
void process(int) { }
};
struct Bar
{
// comment out either of these to compile
explicit Bar(std::function<void(int)>) {}
explicit Bar(std::function<void(short)>) {}
};
int main()
{
Foo f;
Bar b(std::bind(&Foo::process, &f, 1));
return 0;
}
Making the constructor explicit has nothing to do with the arguments having to match exactly! The affect of making a constructor explicit means that it won't be used to implicitly convert an object of a different type the type Bar using this constructor. However, if you try to initialize a Bar object using direct initialization (i.e., Bar(x)), both constructors will be considered.
The result of std::bind() is certainly not a std::function<Signature>, i.e., it doesn't match either of your constructors exactly. Since there is a non-explicit constructor for std::function<Signature> which works for function objects, both signatures do match: the produced bind expression doesn't require any parameter but it can take arguments, i.e., any argument type also cannot be used to distinguish which of the two constructors of Bar should match. Even if the bind expression would require one argument, I don't think it would be used to prefer one constructor over another.

How does constructor conversion work in C++?

How does constructor conversion work?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
produces the output
One
Two(const One&)
f(Two)
Any constructor that can be called with a single argument is considered an implicit conversion constructor. This includes simple 1-argument cases, and usage of default arguments.
This conversion is considered in any context that wants X and provided Y, and Y has such implicit conversion possibility. Note that a plenty of other, built-in conversions also play as a mix (like adjusting const-ness, integral and fp promotions, conversions, etc.) The rule is that at most one "user defined" implicit conversion is allowed in the mix.
In some cases it may be quite surprising, so the general advice is to make any such ctors explicit. That keyword makes the conversion possible but not implicitly: you must use T() syntax to force it.
As an example consider std::vector that has a ctor taking size_t, setting the initial size. It is explicit -- otherwise your foo(vector<double> const& ) function could be mistakenly called with foo(42).
It's right result. Since constructor is not explicit - implicit conversion works (here One is implicitly converted to Two).
one is created, then when passed to f converted to Two.
What the Two(const One&) {cout<<"Two(const One&)"<<endl;} constructor means is that you're allowed to construct a Two value at any time - implicitly - from a One. When you call f(one) it wants a Two parameter, it's given a One, so the compiler puts 2 and 2 together and says "I'll make a temporary Two from the One and complete the call to f()"... everyone will be happy. Hurray!
Compiler has to create copy of Two instance on stack. When you call f() with argument which is object of class One (or any other) compiler looks to definition of class Two and tries to find constructor which takes One(or any other) object(or reference) as an argument. When such constructor has been found it constructs object using it. It's called implicit because compiler do it without your interference.
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
Output will be:
Foo(int number)
f(Foo)