C++ function definition and variable declaration mismatch? - c++

Consider this very simple code:
#include <memory>
class Foo
{
public:
Foo() {};
};
class Bar
{
public:
Bar( const std::shared_ptr<Foo>& foo ) {}
};
int main()
{
Foo* foo = new Foo;
Bar bar( std::shared_ptr<Foo>( foo ) );
return 0;
}
Why does Visual Studio reports
warning C4930: 'Bar bar(std::shared_ptr<Foo>)': prototyped function not called (was a variable definition intended?)
and there is no bar object created...how can this line Bar bar( std::shared_ptr<Foo>( foo ) ); be interpreted as a function definition?
I checked Do the parentheses after the type name make a difference with new? and also C++: warning: C4930: prototyped function not called (was a variable definition intended?), but I feel my problem is different here as I did not use the syntax Foo() nor Bar().
Edit: Note that it successfully compiles:
Foo* foo = new Foo;
std::shared_ptr<Foo> fooPtr( foo );
Bar bar( fooPtr );

This issue is about C++'s most vexing parse. The statement:
Bar bar( std::shared_ptr<Foo>( foo ) );
declares a function called bar that returns Bar and takes an argument called foo of type std::shared_ptr<Foo>.
The innermost parenthesis have no effect. It is as if you would have written the following:
Bar bar( std::shared_ptr<Foo> foo);
Assuming C++11 (since you are already using std::shared_ptr) you could use the brace syntax instead of parenthesis:
Bar bar(std::shared_ptr<Foo>{foo});
This would actually construct an object bar of type Bar, since the statement above can't be interpreted as a declaration because of the braces.

Related

Initialize a C++ class using its constructor inside another Classes constructor that references it

I have a class Foo that references Bar:
class Foo {
Bar &bar;
};
and bar requires an int& to be constructed:
Class Bar {
Bar(int& required_int);
}
I want to be able to initialize Bar when I initalize Foo, but I cannot seem to do so using either of the following:
Foo::Foo(int &my_int) : bar(my_int) {
//...
}
Foo::Foo(int &my_int) : bar(new Bar(my_int)) {
//...
}
Because the compiler complains that whatever is inside bar(...) must be an lvalue. Is this initalization chaining possible? I don't see how bar(...) could ever contain an lvalue if my instance of Bar doesn't exist yet.
class Foo {
Bar & bar;
};
Here bar can only refer to an existing Bar object as it's a reference. You cannot initialize it yourself in Foo class. So, a valid ctor would be similar to this:
Foo::Foo(Bar & existingBar) : bar(existingBar){}
If you want Foo class to have its own independent Bar object, then remove the reference and initialize it like you're doing already.

why can't I directly call a method of an instance which is accessed by pointer-to-member

For example I got a inner class:
struct Foo {
void test() {}
};
and a outer class:
struct Bar {
Foo foo;
};
then in main():
Bar bar{};
Foo Bar::* pFoo = &Bar::foo;
bar.*pFoo.test(); // does not work
Foo foo = bar.*pFoo;
foo.test(); // works;
the error about bar.*pFoo.test() is:member reference base type 'Foo Bar::*' is not a structure or union, so what's the different between bar.*pFoo.test(); and Foo foo = bar.*pFoo; foo.test();?
As hinted at in the comments, .* has lower operator precedence than ..
Thus bar.*pFoo.test(); is parsed as bar.*(pFoo.test()); and is trying to access the test member of pFoo.
Since pFoo is a member pointer of type Foo Bar::* this is not a valid expression. Only class-types can appear on the left-hand side of the member access operator . (pseudo-destructor call syntax aside), which a member pointer is not.
The second example is equivalent to the expression (bar.*pFoo).test(); instead.

Calling a constructor with no parameters works, with a parameter doesn't. Why?

I have a class defined as follows:
class Foo {
private:
boolean feature;
public:
Foo(boolean feature) : feature(feature) {}
// ...
};
I'm trying to construct an instance, as a private property of another class:
class Bar {
private:
Foo foo(true);
// ...
};
This doesn't work. I get expected identifier before numeric constant on the line with the declaration. When I remove the parameter from Foo's constructor definition simply and ask for a Foo foo;, it works.
Why?
How do I define and declare an instance of Foo that takes a boolean parameter?
You can't use that initialisation syntax in a class member declaration; you can only initialise members with {} or =. The following should work (assuming support for C++11 or later):
Foo foo{true};
Foo foo = Foo(true);
The pre-C++11 way to do this is:
class Bar {
public:
Bar() : foo(true){} //initialization
private:
Foo foo; //no parameter
};
Bonus:
class Bar {
private:
Foo foo(); //<- This is a function declaration for a function
//named foo that takes no parameters returning a Foo.
//There is no Foo object declared here!
};

How to initialize const circular reference members

For example, I have two classes
class Foo;
class Bar;
class Foo {
const Bar &m_bar;
...
};
class Bar {
const Foo &m_foo;
...
};
Let foo is object of Foo and bar is object of Bar. Is there any way (normal or "hacking") to create/initialize foo and bar that their members m_bar and m_foo would referenced to each other (I mean foo.m_bar is bar and bar.m_foo is 'foo')?
It is allowed to add any members to Foo and Bar, to add parents for them, to make they templates and so on.
What is the linkage of foo and bar? If they have external
linkage, you can write something like:
extern Foo foo;
extern Bar bar;
Foo foo( bar );
Bar bar( foo );
(I'm assuming here that it is the constructors which set the
reference to a parameter.)
This supposes namespace scope and static lifetime, of course
(but an anonymous namespace is fine).
If they are class members, there's no problem either:
class Together
{
Foo foo;
Bar bar;
public:
Together() : foo( bar ), bar( foo ) {}
};
If they're local variables (no binding), I don't think there's
a solution.
EDIT:
Actually, the local variables have a simple solution: just
define a local class which has them as members, and use it.
This can't work if i understand your Problem correctly, since to create an Object Bar you need Foo and vice versa.
You must not use References but an Pointer instead. Where you can create both Objects separatley and then set Bar to Foo and Foo to Bar.
class Foo
{
public:
Foo();
void setBar( const Bar* bar ){ _bar = bar; }
private:
const Bar* _bar;
}
// class Bar analog to Foo
void xxx:something(void)
{
Foo* f = new Foo;
Bar* b = nee Bar;
f->setBar(b);
b->setBar(f);
...
}

class Bar { operator Foo(); }

What does this style of operator overloading mean?
class Foo {
Foo(int a) { ... }
};
class Bar {
operator Foo() { return Foo(25); }
};
That is user-defined conversion function which converts an instance of Bar into Foo implicitly.
Bar bar;
Foo foo = bar; // bar implicitly converts into Foo.
It is as if you've written this:
Foo foo = Foo(25);
If you've such a conversion function, then you can call this:
void f(Foo foo); //a function which accepts Foo
f(bar); // bar implicitly converts into Foo.
So such implicit conversion may not be desirable sometime, as it might cause problem, producing unintended result. To avoid that, you can make the conversion function explicit as (in C++11 only):
//valid in C++11 only
class Bar {
explicit operator Foo() { return Foo(25); }
};
Now both of these would give error:
Foo foo = bar; //error
f(bar); //error
However, the following is allowed:
Foo foo = static_cast<Foo>(bar); //Ok
f(static_cast<Foo>(bar)); //Ok
It's an overload of the cast operator. Best documentation I could find was MSDN
Basically, if you have a Bar you can cast it to a Foo which is constructed with a specific value:
Bar b;
Foo f = b;