4

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 );
cpplearner
  • 13,776
  • 2
  • 47
  • 72
jpo38
  • 20,821
  • 10
  • 70
  • 151

1 Answers1

14

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.

JFMR
  • 23,265
  • 4
  • 52
  • 76
  • 3
    You mean it's equivalent to `Bar bar( std::shared_ptr foo );`? – jpo38 Sep 14 '17 at 12:18
  • 2
    Correct, but could be a better answer if you had an explanation or link about the Most Vexing Parse and offered a solution. – aschepler Sep 14 '17 at 12:20
  • A possible C++98 or TR1 solution is to use double parentheses after the intended variable name. A parameter name can be enclosed in gratuituous parentheses, as you pointed out, but not the whole parameter list, even if it contains only one parameter declaration. So, e.g.: ``Bar bar((std::tr1::shared_ptr(foo)))``. Not very readable though… – Arne Vogel Sep 14 '17 at 14:55