views:

155

answers:

4

I've got another problem when trying to overload the () operator for array access:

const OctTreeNode*& operator()(const int i, const int j, const int k) const{ 
 return m_cells[k*m_resSqr+j*m_res+i];
}

OctTreeNode*& operator()(const int i, const int j, const int k){ 
 return m_cells[k*m_resSqr+j*m_res+i];  
}

vector<OctTreeNode*> m_cells;

I get a

C2440 'return': cannot convert from 'OctTreeNode *const' to 'const OctTreeNode *&'

what's the deal? i'm declaring it exactly as in another class. the only difference is that the other class is generic, and there i'm using T& instead of OctreeNode*&

+2  A: 

The first operator should return const

const OctTreeNode * const & operator()(const int i, const int j, const int k) const{ 
        return m_cells[k*m_resSqr+j*m_res+i];
}

... or the const before the *, I never seem to remember -_-

First const tells us that we can't modify OctTreeNode, second one tells us that we can't modify the pointer to it (set it to NULL for example) while the third one tells us that the method doesn't change the object.

To be honest I'm unsure wether the first one is needed, as the only thing that we need to grant const correctness to the method, is to grant that nobody will change references to those pointers.

Kornel Kisielewicz
genesys
three consts in one expression make me confused about what those consts actually mean
genesys
expanded my answer
Kornel Kisielewicz
@genesys, the function is `const` so it means that the reference you return can't be modified. The `const` adter the `*` means the pointer itself can't change, which is required for constness. The first `const` means the `OctTreeNode` itself can't change. This `const` isn't actually required, but for semantic `const`ness is recommended.
rlbond
A: 

There is very little point in passing by const value, as you're doing with i, j, k.

Autopulated
Try to tell such things in comments as this isn't an answer to the real problem.
pmr
Sorry, haven't really got the hang of this place yet :)
Autopulated
I sometimes pass my value parameters as const. This helps me for two reasons - If I mistakenly try and mutate one, the compiler will inform me and secondly the semantics are now clearer. The only drawback is function is visually larger and cognitively will likely take longer to understand.
Stephen Nutt
@Stephen: As that const does not change the function other than for the compiler to check internally, you will find people suggesting using non-const signature in the header declaration (`void f( int );`) while const signature in the implementation ( `void f( const int ) {...}`). This will provide a clean API (your users don't really care whether you change or not internally the copied argument, while allowing the compiler to detect the type of mistakes you talk about. And changing that into a non-const argument (if you want to change the argument internally) won't change the header.
David Rodríguez - dribeas
A: 

The constant operator is incorrect, you are returning a non-constant reference to a pointer to a constant OctTreeNode.

That is, if you declare a pointer as

const int *a;

a is not constant, what a points to is constant. So when you declare the return type as

const OctTreeNode*&

the OctTreeNode is constant, but the pointer is not. This is an error because your member function is const, so the std::vector is const, and so the pointer that it returns is also constant - ultimately you try to return a const-pointer as a non-const pointer.

To correct this just remove the reference

const OctTreeNode* operator()

because there's not much point returning a reference to a constant pointer, you can't modify the pointer and the reference will (probably) have the same size as the pointer anyway.

Adam Bowen
Steve Jessop
That's true, but off the top of my head I can't think of anywhere it would be useful - if you need to take the address of it you're probably going to want to change it.
Adam Bowen
Steve Jessop
+1  A: 

Kornel is correct. To clarify should the const be before or after the *, after. The two types const OctTreeNode * const & and OctTreeNode const * const & are identical, both are easily understood when read from right to left.

const OctTreeNode * const & is a reference to a const point to an OctTreeNode that is const.

OctTreeNode const * const & is a reference to a const pointer to a const OctTreeNode.

Note that these types are different from the invalid type const OctTreeNode const * &. This would be a reference to a pointer to a const OctTreeNode that is const.

Notice the last part of the sentence a const OctTreeNode that is const. One of the const is redundant, and this type, had it been legal, would be equivalent to const const OctTreeNode * &

Stephen Nutt