 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
rdnewman Guest
|
Posted: Sat Sep 25, 2004 5:32 am Post subject: Template, types, and []... Oh my! |
|
|
I have a templated class (call it T) which is derived from a std::vector.
This class extends std::vector with a couple of desired methods. I have
two more classes (TA and TB) which are derived from T and serve to
instantiate the template into normal classes. This is so far fine and
solves the immediate problem it was written for. Note however, being
templated, I can't say that TA derives from T; rather it derives from T<A>
and likewise for TB.
I'm sorry for the alphabet soup, but this is proprietary code I'm working
on.
Now another class G contains the following declarations:
TA a;
TB b;
So this G class has-a two objects that instantiated TA and TB. This too
is fine and well.
Let's instantiate G into a real object so I can discuss it:
G g;
Previously, I had two methods:
const TA& getTA() const;
const TB& getTB() const;
They could retrieve the information if I needed to examine the respective
classes. Right now, I can say g.getTA() when I want to look at g.a. But
this isn't as flexible as I'd like for client code.
I'd like to have the same accessor functionality there using the operator
[] such that I can write g[x] where x is a designation to pull either a or
b. This of course is handy when you want to pass x in as an argument to
some method and have it call g[x] to return the right thing to you.
Whether or not, it uses the operator [] function, the same problem exists
if I want any method to take a similar typed argument and return a
non-similar type.
Conceptually simple, but now I realize rather difficult.
The form of a declaration of operator [] is, of course,
returnType operator [] (someType arg).
But here I'd need to say
const TA& operator [] (uh, what goes here?); and
const TB& operator [] (uh....);
This of course can't work since overloading by return types isn't
supported. The more conventional approach for non-templated return values
would be to define a public enum (say E) that defines AA and BB of type E
so that my
operator declaration is
const ReturnType& operator[E arg];
The problem of course is that my return type has to be changed given the
value of E.
Templating this operator is messy for client code to use and makes the
value of using E and [] pretty much lost.
The following is my best, though not good, solution so far (and I'm not
even sure that it'll work):
class G {
public:
class M { };
class AA : class M { };
class BB : class M { };
enum { sayA=0, sayB, sayMAX };
static const M m[sayMAX];
static const AA aa;
static const BB bb;
const TA& operator[](AA arg) { return a; }
const TB& operator[](BB arg) { return b; }
|
|
| Back to top |
|
 |
Maxim Yegorushkin Guest
|
Posted: Sun Sep 26, 2004 4:06 pm Post subject: Re: Template, types, and []... Oh my! |
|
|
rdnewman <richard (AT) cdres (DOT) com> wrote:
[]
| Quote: | I'd like to have the same accessor functionality there using the operator
[] such that I can write g[x] where x is a designation to pull either a
or
b. This of course is handy when you want to pass x in as an argument to
some method and have it call g[x] to return the right thing to you.
Whether or not, it uses the operator [] function, the same problem exists
if I want any method to take a similar typed argument and return a
non-similar type.
|
There are two options.
First, if you want a non-templated function to work with objects of both
types you either have to branch function's code on the type of the object,
or have that objects to expose the same interface for the function to
operate in a generic way.
Example of using of an interface:
struct itf
{
virtual void foo() = 0;
virtual void bar() = 0;
};
struct TA : T, ift
{
void foo() {...}
void bar() {...}
};
// the same for TB
TA a;
TB b;
enum AB { A, B };
itf& get(AB t)
{
switch(t)
{
case A: return a;
case B: return b;
}
};
void f(AB t)
{
get(t).foo();
get(t).bar();
}
The second option is to use a templated function f. You don't necessarily
need an explicit interface here, but both TA and TB must provide the same
functions and possibly same semantics for f to use.
enum AA { A };
enum BB { B };
TA& get(AA) { return a; }
TB& get(BB) { return b; }
template<class T> void f(T t)
{
get(t).foo();
get(t).bar();
}
void g()
{
f(A);
f(B);
};
--
Maxim Yegorushkin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gareth Stockwell Guest
|
Posted: Mon Sep 27, 2004 8:19 pm Post subject: Re: Template, types, and []... Oh my! |
|
|
Richard,
| Quote: | I have a templated class (call it T) which is derived from a std::vector.
|
Just a warning, in case you didn't know - STL containers typically do
not have virtual destructors, so are not intended to be used as base
classes. If T has a non-trivial destructor, you may run into problems
if it does not get called.
Gareth
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Mon Sep 27, 2004 9:11 pm Post subject: Re: Template, types, and []... Oh my! |
|
|
"rdnewman" <richard (AT) cdres (DOT) com> wrote
| Quote: | I have a templated class (call it T) which is derived from a
std::vector.
|
Deriving from the standard containers isn't usually a good idea,
although I suppose that there are exceptions.
| Quote: | This class extends std::vector with a couple of desired
methods. I have two more classes (TA and TB) which are derived from T
and serve to instantiate the template into normal classes. This is so
far fine and solves the immediate problem it was written for. Note
however, being templated, I can't say that TA derives from T; rather
it derives from T<A> and likewise for TB.
I'm sorry for the alphabet soup, but this is proprietary code I'm
working on.
Now another class G contains the following declarations:
TA a;
TB b;
So this G class has-a two objects that instantiated TA and TB. This
too is fine and well.
Let's instantiate G into a real object so I can discuss it:
G g;
Previously, I had two methods:
const TA& getTA() const;
const TB& getTB() const;
They could retrieve the information if I needed to examine the
respective classes. Right now, I can say g.getTA() when I want to
look at g.a.
|
Which, if I understand correctly, is really a T<A>.
| Quote: | But this isn't as flexible as I'd like for client code.
I'd like to have the same accessor functionality there using the
operator [] such that I can write g[x] where x is a designation to
pull either a or b. This of course is handy when you want to pass x
in as an argument to some method and have it call g[x] to return the
right thing to you. Whether or not, it uses the operator [] function,
the same problem exists if I want any method to take a similar typed
argument and return a non-similar type.
|
Let me see if I've understood correctly. What you want is to call g[x],
and have the overloaded operator[] selected by return type.
This isn't possible, but you can get almost the same effect by means of
a proxy, provided the return types are different enough to avoid
ambiguities. Just have operator[] return something like:
class Proxy
{
public:
explicit Proxy( G& owner, size_t index )
: myOwner( &owner )
, myIndex( index )
{}
operator A() const
{
return owner->getA[ myIndex ] ;
}
operator B() const
{
return owner->getB[ myIndex ] ;
}
A& operator=( A const& rhs ) const
{
owner->getA[ myIndex ] = rhs ;
return owner->getA[ myIndex ] ;
}
B& operator=( B const& rhs ) const
{
owner->getB[ myIndex ] = rhs ;
return owner->getB[ myIndex ] ;
}
private:
G* myOwner ;
size_t myIndex ;
} ;
Proxy
G::operator[]( size_t index )
{
return Proxy( *this, index ) ;
}
For a const version, just convert the references and pointers to G to
const, and omit the operator=.
Note that it is important for the target type to be unamguously
identifiable for this to work. If the user writes:
(void)g[ 5 ] ;
the compiler will complain. It will also complain if both A and B are
convertible to int, and the user writes:
int i = g[ 5 ] ;
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
rdnewman Guest
|
Posted: Wed Sep 29, 2004 9:41 am Post subject: Re: Template, types, and []... Oh my! |
|
|
Hello,
My comments below.
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: |
Deriving from the standard containers isn't usually a good idea,
although I suppose that there are exceptions.
|
Thank you (and others) for the warning about deriving from STL containers.
I've revamped my approach so T wraps the vector instead of deriving from
it. A little less elegant than I had hoped for, but the semantics for the
rest of my design should still be fine. To help ease its use, I have
added a conversion operator in the wrapper to expose the wrapped vector
so
that the vector operations are still available. Hopefully this will
provide somewhat the same effect I was going for.
| Quote: |
They could retrieve the information if I needed to examine the
respective classes. Right now, I can say g.getTA() when I want to
look at g.a.
Which, if I understand correctly, is really a T<A>.
|
Correct. g.getTA() essentially returns a T<A> type. This is still true
under the wrapper approach since T still is a template (so that the
wrapped vector can be instantiated with the correct element type).
| Quote: |
But this isn't as flexible as I'd like for client code.
I'd like to have the same accessor functionality there using the
operator [] such that I can write g[x] where x is a designation to
pull either a or b. This of course is handy when you want to pass x
in as an argument to some method and have it call g[x] to return the
right thing to you. Whether or not, it uses the operator [] function,
the same problem exists if I want any method to take a similar typed
argument and return a non-similar type.
Let me see if I've understood
correctly. What you want is to call g[x],
and have the overloaded operator[] selected by return type.
|
Yes, obviously not normally possible to differentiate on conventional
overloads, but yet so tempting semantically.
| Quote: |
This isn't possible, but you can get almost the same effect by means of
a proxy, provided the return types are different enough to avoid
ambiguities. Just have operator[] return something like:
|
Cool! Thank you for this approach and the example code.
I have one more question. In my original description, G is the owner and
already has the following functions:
const T<A>& getTA() const;
const T<B>& getTB() const;
I see that your algorithm works very nearly like the effect I was going
for. As I read it, it works, in part, by using the conversation operators
to perform (from the client code perspective) an implicit conversion to
the
intended type. However, in those operators, you have the statement
"return owner->getA[ my Index ] ;".
These subscripts surprised me for a bit. At first, I wondered why I
wouldn't just use the statement "return owner->getTA();"
instead. However, I think your approach is saying to use a
symbolic-constant argument to getTA such as "return owner->getTA( my Index
) ;".
Such an argument would assure that type checking could be done in the
owner code where it belongs rather than in the proxy code.
Am I interpreting this correctly or have I missed something?
| Quote: | ... Just have operator[] return something like:
class Proxy
{
public:
explicit Proxy( G& owner, size_t index )
: myOwner( &owner )
, myIndex( index )
{}
operator A() const
{
return owner->getA[ myIndex ] ;
}
operator B() const
{
return owner->getB[ myIndex ] ;
}
A& operator=( A const& rhs ) const
{
owner->getA[ myIndex ] = rhs ;
return owner->getA[ myIndex ] ;
}
B& operator=( B const& rhs ) const
{
owner->getB[ myIndex ] = rhs ;
return owner->getB[ myIndex ] ;
}
private:
G* myOwner ;
size_t myIndex ;
} ;
Proxy
G::operator[]( size_t index )
{
return Proxy( *this, index ) ;
}
For a const version, just convert the references and pointers to G to
const, and omit the operator=.
|
Understood.
| Quote: |
Note that it is important for the target type to be unamguously
identifiable for this to work. If the user writes:
(void)g[ 5 ] ;
the compiler will complain. It will also complain if both A and B are
convertible to int, and the user writes:
int i = g[ 5 ] ;
|
Thank you for the warning. I think for this case, it won't be a problem.
Thank you again for your help.
Kind regards,
Richard
Richard Newman
Crowley Davis Research, Inc.
Eagle, ID, USA
www.cdres.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Oct 01, 2004 11:39 am Post subject: Re: Template, types, and []... Oh my! |
|
|
"rdnewman" <richard (AT) nospam (DOT) cdres.com> wrote
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote:
Deriving from the standard containers isn't usually a good idea,
although I suppose that there are exceptions.
Thank you (and others) for the warning about deriving from STL
containers. I've revamped my approach so T wraps the vector instead of
deriving from it. A little less elegant than I had hoped for,
|
If by less elegant, you mean that there is a lot of boilerplate code,
you're right. For the rest, however, I have never had a problem with
this approach, nor do I find it particularly inelegant.
| Quote: | but the semantics for the rest of my design should still be fine. To
help ease its use, I have added a conversion operator in the wrapper
to expose the wrapped vector so that the vector operations are still
available. Hopefully this will provide somewhat the same effect I was
going for.
|
So the presence of the arrays in the form of std::vector is part of the
contract of your class. Typically, such things are implementation
details. (But only typically -- there are definitely exceptions.)
One thing I've found more or less useful when such arrays are to be
exposed to the user is to use typedef's. All I guarantee is that the
type is an STL sequence, or something like that. And user code is
supposed to use the typedef, and only the guaranteed operations. In
theory, at least, this allows me to change the type later, without
breaking user code.
[...]
| Quote: | I have one more question. In my original description, G is the owner
and already has the following functions:
const T<A>& getTA() const; const T<B>& getTB() const; I see that your
algorithm works very nearly like the effect I was going for. As I read
it, it works, in part, by using the conversation operators to perform
(from the client code perspective) an implicit conversion to the
intended type.
|
Right. It's not quite the same thing, since the use involves an
implicit user-defined conversion. Thus, if A also converts into an
std::string, something like "std::string s = v[ n ] ;" would be legal
with an std::vector, but not with your class and the proxy (since with
the proxy, there would be two user defined conversions). Other than
that, however, the technique works pretty well. (Another constraint is
that the user cannot take the address of the object, nor use it to
initialize a non-const reference, e.g. &g[n] is illegal, if g has the
type of your object.)
The real trick, of course, is in the particular semantics of
operator=(), which don't modify the Proxy object, but the object for
which it is a proxy. Anytime you see an operator= which is a const
function, look for something like this -- I think that a const operator=
is a pretty sure sign of a proxy.
(If memory serves me correctly, I learned the technique from Steve
Clamage, something like twelve years ago. I think he prefaced his
presentation to me with something like "The usual technique is...",
which would suggest that it was around even before he presented it to
me. I also have a recollection of it being presented in one of Scott
Meyer's books, but it's been long enough since I read them that I'm no
longer sure.)
| Quote: | However, in those operators, you have the statement "return
owner->getA[ my Index ] ;".
|
Which looks like a typo for "return owner->getA()[ myIndex ] ;".
| Quote: | These subscripts surprised me for a bit. At first, I wondered why I
wouldn't just use the statement "return owner->getTA();" instead.
However, I think your approach is saying to use a symbolic-constant
argument to getTA such as "return owner->getTA( my Index ) ;".
Such an argument would assure that type checking could be done in the
owner code where it belongs rather than in the proxy code.
|
Yes. In my own code, I generally have a function getAt, which takes the
index, does whatever checking is desired, and returns a copy of the
value. And putAt for writing.
| Quote: | Am I interpreting this correctly or have I missed something?
... Just have operator[] return something like:
class Proxy
{
public:
explicit Proxy( G& owner, size_t index )
: myOwner( &owner )
, myIndex( index )
{}
operator A() const
{
return owner->getA[ myIndex ] ;
}
|
This is definitly a typo. My intent was to use your getA and getB
functions. But in that case, it should be:
return owner->getA()[ myIndex ] ;
My usual approach would be more along the lines of:
return owner->getAat( myIndex ) ;
Where getAAt does bounds checking and whatever, and returns a copy
(return by value) of the object.
| Quote: | operator B() const
{
return owner->getB[ myIndex ] ;
}
A& operator=( A const& rhs ) const
{
owner->getA[ myIndex ] = rhs ;
return owner->getA[ myIndex ] ;
|
Again, the idea here was to use your getA and getB functions, but I
forgot the (). And my usual approch would be slightly different:
Proxy&
Proxy::operator=( A const& rhs ) const
{
owner->putAAt( myIndex, rhs ) ;
return *this ;
}
Again, this puts all of the processing in the owner. This is really the
initial motivation for the Proxy, at least in my case. I was
implementing an array in which the actual data were cached on disk,
rather than being maintained in memory; it was important for the parent
to know exactly when the cached data were modified, in order to know
when it had to write back to disk. I've also used this technique in a
COW implementation of String -- the copy only took place in the putAt
function.
| Quote: | }
B& operator=( B const& rhs ) const
{
owner->getB[ myIndex ] = rhs ;
return owner->getB[ myIndex ] ;
}
private:
G* myOwner ;
size_t myIndex ;
} ;
Proxy
G::operator[]( size_t index )
{
return Proxy( *this, index ) ;
}
For a const version, just convert the references and pointers to G
to const, and omit the operator=.
Understood.
Note that it is important for the target type to be unamguously
identifiable for this to work. If the user writes:
(void)g[ 5 ] ;
the compiler will complain. It will also complain if both A and B are
convertible to int, and the user writes:
int i = g[ 5 ] ;
Thank you for the warning. I think for this case, it won't be a problem.
|
It usually isn't. Typically, the only problem that I've seen is people
wanting to do things like &g[5]. But in your case, where g[5] is
intrinsically ambiguous, even that probably won't be a problem.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
rdnewman Guest
|
Posted: Fri Oct 01, 2004 5:23 pm Post subject: Re: Template, types, and []... Oh my! |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: | Deriving from the standard containers isn't usually a good idea,
although I suppose that there are exceptions.
Thank you (and others) for the warning about deriving from STL
containers. I've revamped my approach so T wraps the vector instead
of
deriving from it. A little less elegant than I had hoped for,
If by less elegant, you mean that there is a lot of boilerplate code,
you're right. For the rest, however, I have never had a problem with
this approach, nor do I find it particularly inelegant.
but the semantics for the rest of my design should still be fine.
To
help ease its use, I have added a conversion operator in the wrapper
to expose the wrapped vector so that the vector operations are still
available. Hopefully this will provide somewhat the same effect I
was
going for.
So the presence of the arrays in the form of std::vector is part of the
contract of your class. Typically, such things are implementation
details. (But only typically -- there are definitely exceptions.)
One thing I've found more or less useful when such arrays are to be
exposed to the user is to use typedef's. All I guarantee is that the
type is an STL sequence, or something like that. And user code is
supposed to use the typedef, and only the guaranteed operations. In
theory, at least, this allows me to change the type later, without
breaking user code.
|
Ah, I see where this wrapping is an overall advantage semantically and
actually much cleaner that I realized at first blush. Another arrow for
my quiver...
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
rdnewman Guest
|
Posted: Fri Oct 08, 2004 1:08 am Post subject: Re: Template, types, and []... Oh my! |
|
|
Unfortunately, my last post was not complete. Here is the remainder (did
my last post offend the moderator gods?):
for. As I read
| Quote: | it, it works, in part, by using the conversation operators to
perform
(from the client code perspective) an implicit conversion to the
intended type.
Right. It's not quite the same thing, since the use involves an
implicit user-defined conversion. Thus, if A also converts into an
std::string, something like "std::string s = v[ n ] ;" would be legal
with an std::vector, but not with your class and the proxy (since with
the proxy, there would be two user defined conversions). Other than
that, however, the technique works pretty well. (Another constraint is
that the user cannot take the address of the object, nor use it to
initialize a non-const reference, e.g. &g[n] is illegal, if g has the
type of your object.)
|
In this case, I think this restriction is actually preferred. I mean for
g[n] to be an accessor to the subordinate methods associated with the
particular specialization I intend to return. If they want to hang on to
it for ease of reference, they can take a const reference to what g[n]
returns. "It's not a bug; it's a feature."
| Quote: |
The real trick, of course, is in the particular semantics of
operator=(), which don't modify the Proxy object, but the object for
which it is a proxy. Anytime you see an operator= which is a const
function, look for something like this -- I think that a const
operator=
is a pretty sure sign of a proxy.
(If memory serves me correctly, I learned the technique from Steve
Clamage, something like twelve years ago. I think he prefaced his
presentation to me with something like "The usual technique is...",
which would suggest that it was around even before he presented it to
me. I also have a recollection of it being presented in one of Scott
Meyer's books, but it's been long enough since I read them that I'm no
longer sure.)
|
I see. Good to know, thanks.
| Quote: |
However, in those operators, you have the statement "return
owner->getA[ my Index ] ;".
Which looks like a typo for "return owner->getA()[ myIndex ] ;".
These subscripts surprised me for a bit. At first, I wondered why I
wouldn't just use the statement "return owner->getTA();" instead.
However, I think your approach is saying to use a symbolic-constant
argument to getTA such as "return owner->getTA( my Index ) ;".
Such an argument would assure that type checking could be done in
the
owner code where it belongs rather than in the proxy code.
Yes. In my own code, I generally have a function getAt, which takes
the
index, does whatever checking is desired, and returns a copy of the
value. And putAt for writing.
|
Now here's where I'm still confused and could still use some hand-holding.
Originally, my choice to use separate getA() and getB() functions was
because the function names differentiated the calls so that they could
return different types, since I had nothing in the argument list that
could do this for me if I used more conventional overloading.
Now I see the value of returning the given index as an argument so that,
say, getA() can determine whether it should respond or throw an exception
for a logic problem (more of a sanity check than anything). That is what
I thought you meant initially and thought any typo was in using square
brackets instead of parentheses.
Now I'm interpreting your use of "...getA()[ myIndex ]" as suggesting some
kind of function array. I'm back to being confused now, since I'm not
sure that I'm parsing this syntax right. I'm sorry for being obtuse, but
I think this is probably a critical point in my learning the crux of this
technique.
Now it occurs to me that, instead, your intent may be with [ myIndex ] to
pass an index value to the underlying collection that I'm attempting to
return. So let me back up to make sure we're on the same page and forgive
me if this is already obvious to you.
My G class has two (this number appears to be fairly static for now)
member objects: TA and TB which both happen to be collections (as I
originally had them derived from std::vector but now are simply objects
that own vectors). Conceptually, TA and TB are quite similar in form and
function but necessarily are separate types and this, of course, is my
complication.
So let G have two symbol constants such as "enum {ANA = 0, ANB};" (I think
I used sayA and sayB before for these). So then the call
"const A& a = G[ANA];" could access the A member of G (as a const
reference) and similiarly to access the B member of G with G[ANB]. That
is, I'm not seeking to return an element of A, but rather to return A as
an element of G.
| Quote: |
This is definitly a typo. My intent was to use your getA and getB
functions. But in that case, it should be:
return owner->getA()[ myIndex ] ;
My usual approach would be more along the lines of:
return owner->getAat( myIndex ) ;
Where getAAt does bounds checking and whatever, and returns a copy
(return by value) of the object.
|
Most everything else you've written supports the logic I've outlined
above, but obviously the call to "return owner->getA()[ myIndex ]" with
the apparent subscript (rather than an argument) has me perplexed. Now
that I reread your use of getAAt( myIndex ), it seems to reflect the
element-of-A approach rather than A-as-an-element-of-G approach I'm going
for.
Mr. Kanze, you are a gentleman and scholar to be helping me so much. Thank
you for sticking with me on this thread. I eagerly await your reply.
Kind regards,
Richard
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Oct 08, 2004 3:05 pm Post subject: Re: Template, types, and []... Oh my! |
|
|
"rdnewman" <richard (AT) nospam (DOT) cdres.com> wrote
[...]
| Quote: | However, in those operators, you have the statement "return
owner->getA[ my Index ] ;".
Which looks like a typo for "return owner->getA()[ myIndex ] ;".
These subscripts surprised me for a bit. At first, I wondered
why I wouldn't just use the statement "return owner->getTA();"
instead. However, I think your approach is saying to use a
symbolic-constant argument to getTA such as "return owner->getTA(
my Index ) ;".
Such an argument would assure that type checking could be done in
the owner code where it belongs rather than in the proxy code.
Yes. In my own code, I generally have a function getAt, which takes
the index, does whatever checking is desired, and returns a copy of
the value. And putAt for writing.
Now here's where I'm still confused
|
Actually, I think part of the confusion is on my side. The problem is
that there are too many versions of getA() floating around.
At one point, it was in my mind that you could return a reference to the
underlying container (which if memory serves me right, was essentially
an std::vector). If you do this, then you still need to index it, i.e.:
return owner->getTA()[ myIndex ] ;
Alternatively (and perhaps a better solution), you could do the
deindexing directly in the owner, by providing a getA function. In this
case, you would write:
return owner->getA( myIndex ) ;
| Quote: | and could still use some hand-holding. Originally, my choice to use
separate getA() and getB() functions was because the function names
differentiated the calls so that they could return different types,
since I had nothing in the argument list that could do this for me if
I used more conventional overloading.
Now I see the value of returning the given index as an argument so
that, say, getA() can determine whether it should respond or throw an
exception for a logic problem (more of a sanity check than anything).
That is what I thought you meant initially and thought any typo was in
using square brackets instead of parentheses.
Now I'm interpreting your use of "...getA()[ myIndex ]" as suggesting
some kind of function array. I'm back to being confused now, since
I'm not sure that I'm parsing this syntax right. I'm sorry for being
obtuse, but I think this is probably a critical point in my learning
the crux of this technique.
|
It's my posting which is confusing things. See above: either it is
getTA(), returning a reference to the container, and you have to index
it, or it is getA(), taking the index as a parameter.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|