Topic: Macro offsetof and pointers to members


Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Wed, 4 Oct 2006 22:26:51 CST
Raw View

On Oct 3, 9:50 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> Hi Everybody,
>
> the definition of macro offsetof in the latest publicly available draft
> is: "The macro offsetof(type, member-designator) accepts a restricted
> set of type arguments in this International Standard. If type is not a
> POD structure or a POD union (clause 9), the results are undefined.
> ...
> As the C standard is included for reference, the member-designator could
> be anything that would make the expression "&(t.member-designator)"
> evaluate to an address constant, with t a static variable of the given
> type. So, this code might be expected to work:
>
> template <class Pod, class Type>
> int offset_of(Type Pod::* ptr)
> {
>     return offsetof(Pod, *ptr);
>
> }as the expression "&(t.*ptr)" satisfies the requirements.

No, the expression *ptr fails to meet the C requirements for a
"member-designator" on several counts. For one, *ptr is not a constant
- it is a member pointer variable. And not only must a
member-designator be a constant - it must also be one of the Pod
struct's members - *ptr does not identify one of Pod's members.
Moreover, the syntax for a the member-designator expression
(particularly member-designator's italics) indicates that
member-designator is gramatically an identiifer; so if any operators
were allowed in the expression:

    &(t.member-designator)

they would have to be explicitly included. Since none are present, none
are therefore allowed. In other words, the C standard is not stating
that any expression that evaluates to a pointer to one of the struct's
members is a legal member-designator. On the contrary, it is only after
the criteria for a member-designator are met does this additional
syntactical requirement (namely that &(t.member-designator) evaluate to
constant member address) must also be met.

All other points aside, the principal shortcoming with the expression
offset(Pod, t*.ptr) is that the distance from the starting address of a
structure to a member pointer is not a meaningful concept. In other
words, no program would ever have a reason for using this expression,
since there is nothing useful that the program could do with whatever
value it returned.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 5 Oct 2006 09:41:13 CST
Raw View
Greg Herlihy wrote:
> On Oct 3, 9:50 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
> > Hi Everybody,
> >
> > the definition of macro offsetof in the latest publicly available draft
> > is: "The macro offsetof(type, member-designator) accepts a restricted
> > set of type arguments in this International Standard. If type is not a
> > POD structure or a POD union (clause 9), the results are undefined.
> > ...
> > As the C standard is included for reference, the member-designator could
> > be anything that would make the expression "&(t.member-designator)"
> > evaluate to an address constant, with t a static variable of the given
> > type. So, this code might be expected to work:
> >
> > template <class Pod, class Type>
> > int offset_of(Type Pod::* ptr)
> > {
> >     return offsetof(Pod, *ptr);
> >
> > }as the expression "&(t.*ptr)" satisfies the requirements.
>
> No, the expression *ptr fails to meet the C requirements for a
> "member-designator" on several counts. For one, *ptr is not a constant
> - it is a member pointer variable. And not only must a
> member-designator be a constant - it must also be one of the Pod
> struct's members - *ptr does not identify one of Pod's members.

Could you provide a citation for the requirement that the
member-designator be a struct member? The only requirements I could
find were on the expression &t.member-designator. *ptr doesn't identify
one of Pod's members, but t.*ptr does designate one of t's members,
which seems to be the relevant point.

> Moreover, the syntax for a the member-designator expression
> (particularly member-designator's italics) indicates that
> member-designator is gramatically an identiifer;

I'm sorry - I don't follow that - how are you concluding that the
syntax and italics indicate that it  must be an identifier?

> All other points aside, the principal shortcoming with the expression
> offset(Pod, t*.ptr) is that the distance from the starting address of a
> structure to a member pointer is not a meaningful concept. In other

The expression actually being offered for consideration was
offsetof(Pod, *ptr). To me it seems pretty clear that what it would
identify, if it were legal, is the distance from the starting address
of a POD struct, to the member of that struct that would be pointed at
by the member pointer. That is a perfecly meaningful concept, for a POD
struct. If it were a constant, than &t.*ptr would, in a reasonable
application of C rules in a C++ context, qualify as an address
constant. However, the address of the member pointed at by t*.ptr would
depend upon the value of ptr, so it doesn't qualify.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 5 Oct 2006 10:08:09 CST
Raw View
Greg Herlihy wrote:
> On Oct 3, 9:50 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:

> > the definition of macro offsetof in the latest publicly available draft
> > is: "The macro offsetof(type, member-designator) accepts a restricted
> > set of type arguments in this International Standard. If type is not a
> > POD structure or a POD union (clause 9), the results are undefined.
> > ...
> > As the C standard is included for reference, the member-designator could
> > be anything that would make the expression "&(t.member-designator)"
> > evaluate to an address constant, with t a static variable of the given
> > type. So, this code might be expected to work:

> > template <class Pod, class Type>
> > int offset_of(Type Pod::* ptr)
> > {
> >     return offsetof(Pod, *ptr);

> > }as the expression "&(t.*ptr)" satisfies the requirements.

> No, the expression *ptr fails to meet the C requirements for a
> "member-designator" on several counts. For one, *ptr is not a
> constant - it is a member pointer variable.

Good point.  Whatever else one might say, "&(t.*ptr)" will not
evaluate to an address constant.  Ever, even if ptr is in fact a
constant (i.e. a macro which expands to &Toto::titi).

> And not only must a member-designator be a constant - it must
> also be one of the Pod struct's members - *ptr does not
> identify one of Pod's members.

I think what triggered his posting is precisely that the C
standard doesn't say this.  It doesn't have to, because about
the only thing legal on the right of a . operator is a member.
In C++, something like t.*ptr is a legal expression.  (Although
in this case, I think that the expansion with *ptr cannot to
token pasting, so we end up with something more on the lines of
"t. *ptr", which isn't legal.)

(What also triggered his posting, apparently, is that VC++
accepted the expression.  Which doesn't make it non-conforming,
because violating the rules here is undefined behavior, so the
compiler can do anything.)

> Moreover, the syntax for a the member-designator expression
> (particularly member-designator's italics) indicates that
> member-designator is gramatically an identiifer;

No.  In this context, the fact that member-designator is in
italics indicates that it is a user specified parameter.  And in
fact, sequences of token are definitely legal, and something
like:

    struct S { char a[ 15 ] ; } ;
    // ...
        offsetof( struct S, a[ 5 ] )

is required to work (and in this particular case, the result
must be (size_t)5.

> so if any operators were allowed in the expression:

>     &(t.member-designator)

> they would have to be explicitly included. Since none are
> present, none are therefore allowed. In other words, the C
> standard is not stating that any expression that evaluates to
> pointer to the struct's members is a legall member-designator.
> On the contrary, it is only after the criteria for a
> member-designatre are met does this additional syntactical
> requirement (namely that &(t.member-designator) evaluate to
> constant-address) must also be met.

Note that type is also in italics.  Does this mean that multiple
tokens are also illegal for type?  That would sort of create a
problem in C, where you have to write "struct S", and not just
S.

(I think you're at least partially confused by the fact that the
C standard normally uses a fixed width typography with the exact
syntax of a function prototype in such cases.  In fact, it
deviates from this typography only in cases where we are dealing
with a macro whose parameters cannot possibly be an
expression---the only other case I can find right off is
va_arg.)

> All other points aside, the principal shortcoming with the
> expression offset(Pod, t*.ptr) is that the distance from the
> starting address of a structure to a member pointer is not a
> meaningful concept. In other words, no program would ever have
> a reason for using this expression, since there is nothing
> useful that the program could do with whatever value it
> returned.

I can think of some exotic uses involving templates and
serialization, but I agree in general; there are enough other
ways of confusing someone reading the code that we don't need
this one as well.

--
James Kanze                                           GABI Software
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


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Thu, 5 Oct 2006 16:23:22 GMT
Raw View
Greg Herlihy ha scritto:

> All other points aside, the principal shortcoming with the expression
> offset(Pod, t*.ptr) is that the distance from the starting address of a
> structure to a member pointer is not a meaningful concept. In other
> words, no program would ever have a reason for using this expression,
> since there is nothing useful that the program could do with whatever
> value it returned.

I wasn't trying to compute the distance from the starting address of a
structure to a member pointer, but from the starting address of a
structure to *the member* pointed to by a member pointer.

Anyway, thanks for your comments, it's now more clear to me why offsetof
can't be used for this. Now, let's state my request differently: could
it be conceivable and widely implementable, possibly with some help from
the compiler, a facility like this (using "concepts" notation):

template <Pod P, typename V, V P::*ptr>
size_t offset_of()
{ return implementation-defined-offsetof(P, ptr); }

It might be useful for things like introspection, for example.
Unfortunately, the syntax to use such function is quite cumbersome, in
particular because you need to specify V.

Alternatively:

template <class P, typename V>
site_t offset_of(V P::*ptr)
{ return implementation-defined-offsetof(P, ptr); }

which has the advantage that it could also be evaluated at runtime and
possibly without requiring P to be Pod (these advantages could actually
be disadvantages because they might make the function more difficult to
implement and might need to be dropped).

Or any other facility that might extract the offset from a pointer to
member...

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 5 Oct 2006 11:23:55 CST
Raw View
Alberto Ganesh Barbati wrote:
> kanze ha scritto:

> >> As the C standard is included for reference, the member-designator could
> >> be anything that would make the expression "&(t.member-designator)"
> >> evaluate to an address constant, with t a static variable of the given
> >> type. So, this code might be expected to work:

> >> template <class Pod, class Type>
> >> int offset_of(Type Pod::* ptr)
> >> {
> >>     return offsetof(Pod, *ptr);
> >> }

    [...]
> VC++ defines offsetof like this:

> #define offsetof(s,m)   (size_t)&(((s *)0)->m)

> and the template above works like a charm :-)

> However, if you're right about the token-pasting issue above,
> that would mean the VC++ preprocessor is not conforming, as it
> shouldn't have pasted "->" and "*" into "->*".

What version of VC++?  I just tried the following with VC++ 8.0:

    #include <iostream>
    #include <ostream>

    #define X ++a

    int a = 1 ;
    int b = 2 ;

    int
    main()
    {
        int c = b+X ;
        std::cout << "a = " << a << std::endl ;
        std::cout << "b = " << b << std::endl ;
        std::cout << "c = " << c << std::endl ;
        return 0 ;
    }

And it outputs a = 2, b = 2, c = 4, just like one would expect.
If it were pasting tokens, as you suggest, then the first line
of main() would expand to:

    int c = b+++a ;

which would result in an output of a = 1, b = 3, c = 4.  So it
would seem that the preprocessor usually works correctly?

--
James Kanze                                           GABI Software
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


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 5 Oct 2006 11:23:44 CST
Raw View
Alberto Ganesh Barbati wrote:
> kanze ha scritto:

> >> As the C standard is included for reference, the
> >> member-designator could be anything that would make the
> >> expression "&(t.member-designator)" evaluate to an address
> >> constant, with t a static variable of the given type. So,
> >> this code might be expected to work:

> >> template <class Pod, class Type>
> >> int offset_of(Type Pod::* ptr)
> >> {
> >>     return offsetof(Pod, *ptr);
> >> }

    [...]
> > I'm pretty sure that the intent in the C standard was that the .
> > in the expression be a token, and that there was no intent
> > concerning pure textual substitution.  In the C standard, of
> > course, it wasn't necessary to say this, because the only other
> > token which could contain a dot was ..., and there is no
> > possible way that &(t...whatever) could be a legal expression.

> I understand that in C it wasn't necessary to clarify the
> intent, but in C++ it seems I found a case where a
> clarification might be useful.

I agree that it wouldn't hurt.  For that matter, I think the
intent in C would have been clearer if they'd have separated the
tokens with spaces, i.e. that the requirement was that "& * t .
member-designator" be a legal expression.  In which case, we
wouldn't have to discuss it here.

> > In fact, there is a requirement that offsetof be a macro.
> > And the way macros are expanded, if "&(t.*ptr)" is the
> > result of an expansion where *ptr was an argument to the
> > macro, the . and the * are in fact two separate tokens.

> If I understand it correctly, macro replacement occurs in
> translation phase 4, while the conversion of preprocessing
> tokens into tokens happens in phase 7. So it seems possible to
> me that token-pasting could create a ".*" token out of a "."
> and "*" preprocessing tokens. Am I missing something?

The source file is decomposed into preprocessor tokens in phase
3.  Before even looking for macros.  In phase 7, "Each
preprocessing token is converted into a token."  If you have two
preprocessing tokens, "." and "*", you get two C++ tokens (in
this case, the same).

The design (if one can call it such) of the preprocessor is not
based on textual substitution, but on preprocessor tokens, and
the output is not, conceptually, a stream of text, but a stream
of tokens.  (This is why, for example, the results of ## must be
a valid preprocessor token.)

> >> It actually
> >> works on at least one compiler (VC++ 7.1).

> > I'd be interested in seeing how.  Unless there's some illicit
> > token pasting going on, or the compiler has some sort of
> > extention, I don't see how it could.

> VC++ defines offsetof like this:

> #define offsetof(s,m)   (size_t)&(((s *)0)->m)

> and the template above works like a charm :-)

That's a common definition for offsetof, and they have an error
in their preprocessor.  Whether there is a white space between
the -> and m or not should not make a difference.  The only way
two preprocessor tokens can become a single token is by means of
the ## operator.

> However, if you're right about the token-pasting issue above,
> that would mean the VC++ preprocessor is not conforming, as it
> shouldn't have pasted "->" and "*" into "->*".

I think if you read carefully the phases of translation, then
   16.3, you'll agree with me.  The ## operator was added for a
reason.  (Earlier, pre-standard compilers did have different
behaviors, including perhaps some which had the same behavior as
VC++ today.  But the standard in pre-standard, here, is C90.
Not exactly something new.)  Note, in particular, that macro
replacement is NOT string substitution; at all moments during
macro replacement, we are (conceptually at least) dealing with a
stream of tokens.  (There are exceptions, but even in the #
operator, "the original spelling of each preprocessing token in
the argument is retained", not the original spelling of the
entire expression passed as an argument.)

(The whole issue would be a lot clearer if what was a
preprocessor token wasn't context dependant.  G++, for example,
erroneously rejects the following code:

    #define filename(base,suffix) base ## . ## suffix
    #define sysinclude( f ) <f>

    #include sysinclude(filename(ctype,h))

with the error message:

    paste.cc:11:1: error: pasting "ctype" and "." does not give a valid
preprocessing token
    paste.cc:11:1: error: pasting "." and "h" does not give a valid
preprocessing token

Of course, the expansion is taking place in an include; more
precisely, the only type of preprocessor token which would be
legal here is an h-char-sequence, and ctype. and .h are both
legal h-char-sequence tokens.  The error messages would be
appropriate if filename were called in any other context,
however.  Although not required, since it would be undefined
behavior.)

--
James Kanze                                           GABI Software
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


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 3 Oct 2006 16:50:00 GMT
Raw View
Hi Everybody,

the definition of macro offsetof in the latest publicly available draft
is: "The macro offsetof(type, member-designator) accepts a restricted
set of type arguments in this International Standard. If type is not a
POD structure or a POD union (clause 9), the results are undefined. The
expression offsetof(type, member-designator) is never type-dependent
(14.6.2.2) and it is value-dependent (14.6.2.3) if and only if type is
dependent. The result of applying the offsetof macro to a field that is
a static data member or a function member is undefined."

As the C standard is included for reference, the member-designator could
be anything that would make the expression "&(t.member-designator)"
evaluate to an address constant, with t a static variable of the given
type. So, this code might be expected to work:

template <class Pod, class Type>
int offset_of(Type Pod::* ptr)
{
    return offsetof(Pod, *ptr);
}

as the expression "&(t.*ptr)" satisfies the requirements. It actually
works on at least one compiler (VC++ 7.1).

Is that actually supposed to work?

If yes, then we have a another little problem. Consider a slightly
simpler example:

struct Pod { ... };

template <class Type>
int offset_of(Type Pod::* ptr)
{
    return offsetof(Pod, *ptr);
}

Now the expression offsetof(Pod, *ptr) is value-dependent although Pod
is not dependent, in contraction with the requirement "is
value-dependent if and only if type is dependent". (Notice that in the
example above there were no such contradiction.)

Any thoughts?

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 4 Oct 2006 11:24:07 CST
Raw View
Alberto Ganesh Barbati wrote:

> the definition of macro offsetof in the latest publicly available draft
> is: "The macro offsetof(type, member-designator) accepts a restricted
> set of type arguments in this International Standard. If type is not a
> POD structure or a POD union (clause 9), the results are undefined. The
> expression offsetof(type, member-designator) is never type-dependent
> (14.6.2.2) and it is value-dependent (14.6.2.3) if and only if type is
> dependent. The result of applying the offsetof macro to a field that is
> a static data member or a function member is undefined."

> As the C standard is included for reference, the member-designator could
> be anything that would make the expression "&(t.member-designator)"
> evaluate to an address constant, with t a static variable of the given
> type. So, this code might be expected to work:

> template <class Pod, class Type>
> int offset_of(Type Pod::* ptr)
> {
>     return offsetof(Pod, *ptr);
> }

Since when is *ptr a legal expression when ptr has type pointer
to member?

> as the expression "&(t.*ptr)" satisfies the requirements.

I'm pretty sure that the intent in the C standard was that the .
in the expression be a token, and that there was no intent
concerning pure textual substitution.  In the C standard, of
course, it wasn't necessary to say this, because the only other
token which could contain a dot was ..., and there is no
possible way that &(t...whatever) could be a legal expression.

In fact, there is a requirement that offsetof be a macro.  And
the way macros are expanded, if "&(t.*ptr)" is the result of an
expansion where *ptr was an argument to the macro, the . and the
* are in fact two separate tokens.

> It actually
> works on at least one compiler (VC++ 7.1).

I'd be interested in seeing how.  Unless there's some illicit
token pasting going on, or the compiler has some sort of
extention, I don't see how it could.

> Is that actually supposed to work?

I'm pretty sure that it's not.

> If yes, then we have a another little problem. Consider a
> slightly simpler example:

> struct Pod { ... };

> template <class Type>
> int offset_of(Type Pod::* ptr)
> {
>     return offsetof(Pod, *ptr);
> }

> Now the expression offsetof(Pod, *ptr) is value-dependent although Pod
> is not dependent,

Now I'm confused.  How can something be value-dependent if there
is no value parameter for the template?

> in contraction with the requirement "is value-dependent if and
> only if type is dependent". (Notice that in the example above
> there were no such contradiction.)

--
James Kanze                                           GABI Software
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


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Wed, 4 Oct 2006 19:22:33 GMT
Raw View
kanze ha scritto:
>
>> As the C standard is included for reference, the member-designator could
>> be anything that would make the expression "&(t.member-designator)"
>> evaluate to an address constant, with t a static variable of the given
>> type. So, this code might be expected to work:
>
>> template <class Pod, class Type>
>> int offset_of(Type Pod::* ptr)
>> {
>>     return offsetof(Pod, *ptr);
>> }
>
> Since when is *ptr a legal expression when ptr has type pointer
> to member?

It isn't. But I don't think that's relevant, here. There's no
requirement that *ptr must be a legal expression. In fact even the name
of a member is not a legal expression, it's just a name.

>> as the expression "&(t.*ptr)" satisfies the requirements.
>
> I'm pretty sure that the intent in the C standard was that the .
> in the expression be a token, and that there was no intent
> concerning pure textual substitution.  In the C standard, of
> course, it wasn't necessary to say this, because the only other
> token which could contain a dot was ..., and there is no
> possible way that &(t...whatever) could be a legal expression.

I understand that in C it wasn't necessary to clarify the intent, but in
C++ it seems I found a case where a clarification might be useful.

> In fact, there is a requirement that offsetof be a macro.  And
> the way macros are expanded, if "&(t.*ptr)" is the result of an
> expansion where *ptr was an argument to the macro, the . and the
> * are in fact two separate tokens.

If I understand it correctly, macro replacement occurs in translation
phase 4, while the conversion of preprocessing tokens into tokens
happens in phase 7. So it seems possible to me that token-pasting could
create a ".*" token out of a "." and "*" preprocessing tokens. Am I
missing something?

>> It actually
>> works on at least one compiler (VC++ 7.1).
>
> I'd be interested in seeing how.  Unless there's some illicit
> token pasting going on, or the compiler has some sort of
> extention, I don't see how it could.

VC++ defines offsetof like this:

#define offsetof(s,m)   (size_t)&(((s *)0)->m)

and the template above works like a charm :-)

However, if you're right about the token-pasting issue above, that would
mean the VC++ preprocessor is not conforming, as it shouldn't have
pasted "->" and "*" into "->*".

>> Is that actually supposed to work?
>
> I'm pretty sure that it's not.

I tend to agree with you, although I would rather not in this case ;-)

>> If yes, then we have a another little problem. Consider a
>> slightly simpler example:
>
>> struct Pod { ... };
>
>> template <class Type>
>> int offset_of(Type Pod::* ptr)
>> {
>>     return offsetof(Pod, *ptr);
>> }
>
>> Now the expression offsetof(Pod, *ptr) is value-dependent although Pod
>> is not dependent,
>
> Now I'm confused.  How can something be value-dependent if there
> is no value parameter for the template?

It's me who is very confused. Please forget about that.

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Wed, 4 Oct 2006 21:57:15 CST
Raw View

On Oct 3, 9:50 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> Hi Everybody,
>
> the definition of macro offsetof in the latest publicly available draft
> is: "The macro offsetof(type, member-designator) accepts a restricted
> set of type arguments in this International Standard. If type is not a
> POD structure or a POD union (clause 9), the results are undefined.
> ...
> As the C standard is included for reference, the member-designator could
> be anything that would make the expression "&(t.member-designator)"
> evaluate to an address constant, with t a static variable of the given
> type. So, this code might be expected to work:
>
> template <class Pod, class Type>
> int offset_of(Type Pod::* ptr)
> {
>     return offsetof(Pod, *ptr);
>
> }as the expression "&(t.*ptr)" satisfies the requirements.

No, the expression *ptr fails to meet the C requirements for a
"member-designator" on several counts. For one, *ptr is not a constant
- it is a member pointer variable. And not only must a
member-designator be a constant - it must also be one of the Pod
struct's members - *ptr does not identify one of Pod's members.
Moreover, the syntax for a the member-designator expression
(particularly member-designator's italics) indicates that
member-designator is gramatically an identiifer; so if any operators
were allowed in the expression:

    &(t.member-designator)

they would have to be explicitly included. Since none are present, none
are therefore allowed. In other words, the C standard is not stating
that any expression that evaluates to pointer to the struct's members
is a legall member-designator. On the contrary, it is only after the
criteria for a member-designatre are met does this additional
syntactical requirement (namely that &(t.member-designator) evaluate to
constant-address) must also be met.

All other points aside, the principal shortcoming with the expression
offset(Pod, t*.ptr) is that the distance from the starting address of a
structure to a member pointer is not a meaningful concept. In other
words, no program would ever have a reason for using this expression,
since there is nothing useful that the program could do with whatever
value it returned.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]