views:

75

answers:

4

In this simple example, why do I need to make 'member' const in order to get this to compile?

struct ClassA
{
    ClassA(int integer) {}
};

struct ClassB
{
    ClassB(int integer):
        member(integer)
    {
    }

    const ClassA& member;
};

int main()
{
    ClassB* b = new ClassB(12);

    return 0;
}

Otherwise, I get this error:

error: invalid initialization of reference of type 'ClassA&' from expression of type 'int'

+4  A: 

Because you are trying to store a reference to a temporary object, and you may only store constant references to temporaries.

When you try to initialize the member reference of type ClassA& with the integer parameter of type int, the implicit conversion constructor ClassA::ClassA(int integer) is inovked to produce an unnamed temporary object of type ClassA from the integer variable. That unnamed temporary object is then used to initialize the reference member, creating a reference-to-temporary, which must be const.

I question your design here. If you're trying to initialize member with data passed by value to the ClassB constructor, having member be a reference is probably not the right thing to do. Why do you think member ought to be a reference and not just an object?

Tyler McHenry
A: 

ClassA is a reference member of ClassB, so it must be instantiated with an instance of ClassA.

CharlesB
There is an implicit conversion from `int` to `ClassA` because of it's single valued constructor.
JaredPar
+9  A: 

The reason why is that what's actually happening here is you're using an implicit conversion from int to ClassA in the initialization of member. In expanded form it is actually doing the following

member(ClassA(integer))

This means that the ClassA instance is a temporary. It's not legal to have a reference to a temporary variable only a const reference hence you get the compiler error.

The easiest fix is to remove the & modifier on member and make it just of type ClassA

ClassA member;

Additionally it's a good practice to put explicit in front of the ClassA constructor to avoid the silent implicit conversion.

explicit ClassA(int integer){}
JaredPar
+1 for explicit.
Matthieu M.
A: 

You're create a temporary, and initializing the reference from that temporary. Just like usual, to bind to a temporary, a reference has to be const.

I'd have serious second thoughts about this. A class with a reference member is rarely useful. When it is useful, you generally want to start with some existing object and pass a reference to that object through to the member reference. When you do this, you need to be sure the referenced object exists for the entire lifetime of the object containing a reference, so the two are quite tightly coupled -- which you'd usually rather avoid.

Jerry Coffin