3

Today, while compiling some code with GCC 4.9.2 for the first time, I encountered a strange error about an array being interpreted as an array of references.

I was able to reproduce the error with a quick example. Why is the constructor of Link interpreting buses as an array of references in the constructor of Stuff.

The following code works with MSVC10 and ICC 11.1

#include <iostream> struct Bus { Bus(std::string n) : name(n) {} std::string name; }; template<typename T> class Link { public: Link(const T* i) { data = (T*)i; } const T* get() const { return data; } private: T* data = nullptr; }; class Stuff { public: Stuff(Link<Bus> l_b) : link(l_b) {} private: Link<Bus> link; }; void print(Link<Bus> l) { std::cout << l.get()->name << '\n'; } int main(void) { Bus buses[4] = { Bus("0"), Bus("1"), Bus("2"), Bus("3") }; print(Link<Bus>(&buses[0])); Stuff s(Link<Bus>(&buses[0])); return 0; } 

But with GCC and Clang, this gives an error :

main.cpp: In function 'int main()': main.cpp:44:32: error: declaration of 'buses' as array of references Stuff s(Link<Bus>(&buses[0])); 

Yet, the call to the print function works as intended. I am clueless about why the constructor fails.

I found a solution to that problem, by calling buses lik that in the call to the constructor of Stuff

Stuff s(Link<Bus>((&buses)[0])); 

But I'm really interested to know why it fails.

Live example here

8
  • 9
    Looks like the Most Vexing Parse. Commented Feb 16, 2018 at 15:48
  • 1
    If I rewrite your declaration as Stuff s(Link<Bus>& buses[0]), does it make more sense? Commented Feb 16, 2018 at 15:51
  • Does this work... Stuff s{Link<Bus>(&buses[0])}; ...? Commented Feb 16, 2018 at 15:51
  • Or Stuff s = Stuff(Link<Bus>(&buses[0]));. Commented Feb 16, 2018 at 15:52
  • @Angew its is still not working with a recent GCC wandbox.org/permlink/goDtz3TABvmswhCJ Commented Feb 16, 2018 at 15:55

1 Answer 1

5

You are the victim of the Most Vexing Parse rule.

The compiler sees:

Stuff s(Link<Bus>((&buses)[0])); 

As a function declaration of a function named s that returns a Stuff object and asks for an 0-element array of Link object references.

To fix this and tell the compiler you're actually trying to create a Stuff object you should use the {} syntax to avoid ambiguity:

Stuff s{ Link<Bus>((&buses)[0]) }; 
Sign up to request clarification or add additional context in comments.

8 Comments

Is it the same thing if I call Stuff s(Link<Bus>{&buses[0]}); ?
@Bl4ckb0ne Yes, since that no longer can be a function declaration.
Now my old MSVC fails with the fix. Awesome. Thanks for your explication.
@Bl4ckb0ne If you need this to work with pre C++11 MSVC, surround the constructor argument with parens. That should also work. I.e Stuff s((Link<Bus>(&buses[0])));
Finally a Q&A mentioning the most-vexing parse which is actually about the most-vexing parse :D
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.