reference trouble in double[3] vs. double*

J

Jacek Dziedzic

Hi!

Let's say I have a class called Triplet that serves as an envelope
for double[3], ie.

class Triplet {
public:
Triplet() {/*...*/}
/*
some things that double[3] doesn't have, like
a << operator to send it to a stream
*/

private:
double storage[3];
};

I'm having a problem with the subscript operator, I tried

double& Triplet::eek:perator[](const unsigned int i) const {
return storage;
}

and was quite surprised to see it won't compile. It works
fine, however, when I change
"double storage[3]" to "double *storage" and allocate it
accordingly.

I guess I'm being bitten by the differences between array
of double and pointer to double when it comes to references,
but can someone shed some light on why what I attempted is
not possible? I got away with something like

return (static_cast<double*>(&(storage[0])));

while also making the operator[] non-const, but it sure looks ugly.

So... what is it with the array that doesn't allow what
I'm trying to do? Is there a cleaner way (changing the array
to a pointer and doing new[] will be overkill, I use these
Triplets in huge matrices up to 8100x8100).
 
J

John Harrison

Jacek Dziedzic said:
Hi!

Let's say I have a class called Triplet that serves as an envelope
for double[3], ie.

class Triplet {
public:
Triplet() {/*...*/}
/*
some things that double[3] doesn't have, like
a << operator to send it to a stream
*/

private:
double storage[3];
};

I'm having a problem with the subscript operator, I tried

double& Triplet::eek:perator[](const unsigned int i) const {
return storage;
}

and was quite surprised to see it won't compile. It works
fine, however, when I change
"double storage[3]" to "double *storage" and allocate it
accordingly.


Think about it

const Triplet x;
x[1] = 2.0;

do you really want that to compile?
I guess I'm being bitten by the differences between array
of double and pointer to double when it comes to references,
but can someone shed some light on why what I attempted is
not possible? I got away with something like

return (static_cast<double*>(&(storage[0])));

while also making the operator[] non-const, but it sure looks ugly.

So... what is it with the array that doesn't allow what
I'm trying to do?


Its nothing to do with arrays, returning a non-const reference to any data
member from a const method will not compile.
Is there a cleaner way (changing the array
to a pointer and doing new[] will be overkill, I use these
Triplets in huge matrices up to 8100x8100).

Do it like this

double& Triplet::eek:perator[](const unsigned int i) {
return storage;
}

double Triplet::eek:perator[](const unsigned int i) const {
return storage;
}

i.e. define const and non-const versions of your operator[].

john
 
E

E. Robert Tisdale

John said:
Do it like this

double& Triplet::eek:perator[](const unsigned int i) {
return storage;
}

double Triplet::eek:perator[](const unsigned int i) const {
return storage;
}

i.e. define const and non-const versions of your operator[].


Or

const
double& Triplet::eek:perator[](const unsigned int i) const {
return storage;
}
 
A

Ali Cehreli

Jacek Dziedzic said:
Hi!

Let's say I have a class called Triplet that serves as an envelope
for double[3], ie.

class Triplet {
public:
Triplet() {/*...*/}
/*
some things that double[3] doesn't have, like
a << operator to send it to a stream
*/

You should have a declaration in the commented-out section like this:

double const & operator[] (unsigned int i) const;

Please note that a const member function cannot return a non-const
reference. For that reason, you must declare the return type as
'double' or 'double const &'.

Also note that the 'const' for the argument is not the part of the
signature but an implementation detail, because the 'i' that users
pass will be copied to the function.

For that reason, some argue that it shouldn't take part in the
interface. It doesn't matter really because that top-level const
doesn't take part in the signature of the function.

If you need to provide non-const access too, then you can define the
non-const version:

double & operator[] (unsigned int i);
private:
double storage[3];
};

I'm having a problem with the subscript operator, I tried

double& Triplet::eek:perator[](const unsigned int i) const {
return storage;
}


To match the declaration above, the return type must be 'double const
&' here. Cont-qualifying 'i' is ok here because this is the
implementation.

Ali
 
R

red floyd

Jacek Dziedzic said:
[redacted]

Try:

class Triplet {
//...
double& operator[](unsigned int i) { return storage; }
double operator[](unsigned int i) const { return storage; }
//...
};

Note the different return types for const vs. non-const.
 
O

Old Wolf

Jacek Dziedzic said:
class Triplet {
public:
Triplet() {/*...*/}

double& operator[](const unsigned int i) const
{ return storage; }
private:
double storage[3];
};

I'm having a problem with the subscript operator, I
was quite surprised to see it won't compile. It works
fine, however, when I change "double storage[3]" to
"double *storage" and allocate it accordingly.

If a Triplet is const, then its members are const. So the original
storage is const and you cannot return a non-const reference to it.
But in the case of "double *storage", "storage" is still const but
the things it points to are non-const.

BCC and GCC 2 give a useful error message for the above code:
In method `double & Triplet::eek:perator [](unsigned int) const':
warning: conversion from `const double' to `double &' discards const
but GCC 3's output was obfuscated:
In member function `double& Triplet::eek:perator[](unsigned int) const':
error: could not convert `this->Triplet::storage' to `double&'

One solution is to make two operator[] functions, one being const and
returning const ref, and the other non-const and returning non-const ref.
This is a bit inelegant (especially if you want to support volatile
triplets too), I don't know if there is a better solution.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top