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
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.