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

bl4ckb0ne
  • 1,097
  • 2
  • 15
  • 30

1 Answers1

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]) };
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122