'Walt Karas' via ISO C++ Standard - Future Proposals
6 years ago
That is, casting from a pointer to data member to a pointer to the
containing class instance. Here is an implementation with macros, likely
to have high de facto portability. Putting this capability in the base
language in some way would be more type-safe and more aesthetic.
#include <cstddef>
#include <utility>
// If FIELD_PTR is a pointer to a field specified by FIELD_SPEC in an
instance of a class named CLASS_NAME, then
// FIELD_TO_CLASS_PTR(CLASS_NAME, FIELD_SPEC, FIELD_PTR) returns a pointer
to the instance of CLASS_NAME.
//
// Example:
//
// struct S
// {
// int m, n;
// struct { int a, b, c; } ss;
// int q;
// } s;
//
// assert(FIELD_TO_CLASS_PTR(S, ss.b, &(s.ss.b)) == &s);
//
#define FIELD_TO_CLASS_PTR(CLASS_NAME, FIELD_SPEC, FIELD_PTR)
\
([](decltype(std::declval<CLASS_NAME>().FIELD_SPEC) *fldPtr) ->
CLASS_NAME * { \
return reinterpret_cast<CLASS_NAME *>(reinterpret_cast<char *>(fldPtr)
- offsetof(CLASS_NAME, FIELD_SPEC)); \
}(FIELD_PTR))
// Version for const, volatile, const volatile pointers.
//
// Example:
//
// struct S
// {
// int m, n;
// struct { int a, b, c; } ss;
// int q;
// } s;
//
// const S *sp = &s;
//
// assert(CV_FIELD_TO_CLASS_PTR(const, S, ss.b, &(sp->ss.b)) == sp);
//
#define CV_FIELD_TO_CLASS_PTR(CVSPEC, CLASS_NAME, FIELD_SPEC, FIELD_PTR)
\
([](CVSPEC decltype(std::declval<CLASS_NAME>().FIELD_SPEC) *fldPtr) ->
CVSPEC CLASS_NAME * { \
return reinterpret_cast<CVSPEC CLASS_NAME *>(reinterpret_cast<CVSPEC
char *>(fldPtr) - offsetof(CLASS_NAME, FIELD_SPEC)); \
}(FIELD_PTR))
/*
NOTE: this is generalizing the technique of static_cast'ing from a base
class pointer to a derived class pointer. It
allows this technique with class fields as well as base classes. But it's
easy to make a mistake that the compiler
would not catch unfortunately, must be used very carefully. The lambda
function is used so that at least the compiler
can check that the type of the pointer and the type of the class field
match.
*/
This technique is not strictly necessary, but I have found many cases where
I felt using it made the code clearer and more concise.
containing class instance. Here is an implementation with macros, likely
to have high de facto portability. Putting this capability in the base
language in some way would be more type-safe and more aesthetic.
#include <cstddef>
#include <utility>
// If FIELD_PTR is a pointer to a field specified by FIELD_SPEC in an
instance of a class named CLASS_NAME, then
// FIELD_TO_CLASS_PTR(CLASS_NAME, FIELD_SPEC, FIELD_PTR) returns a pointer
to the instance of CLASS_NAME.
//
// Example:
//
// struct S
// {
// int m, n;
// struct { int a, b, c; } ss;
// int q;
// } s;
//
// assert(FIELD_TO_CLASS_PTR(S, ss.b, &(s.ss.b)) == &s);
//
#define FIELD_TO_CLASS_PTR(CLASS_NAME, FIELD_SPEC, FIELD_PTR)
\
([](decltype(std::declval<CLASS_NAME>().FIELD_SPEC) *fldPtr) ->
CLASS_NAME * { \
return reinterpret_cast<CLASS_NAME *>(reinterpret_cast<char *>(fldPtr)
- offsetof(CLASS_NAME, FIELD_SPEC)); \
}(FIELD_PTR))
// Version for const, volatile, const volatile pointers.
//
// Example:
//
// struct S
// {
// int m, n;
// struct { int a, b, c; } ss;
// int q;
// } s;
//
// const S *sp = &s;
//
// assert(CV_FIELD_TO_CLASS_PTR(const, S, ss.b, &(sp->ss.b)) == sp);
//
#define CV_FIELD_TO_CLASS_PTR(CVSPEC, CLASS_NAME, FIELD_SPEC, FIELD_PTR)
\
([](CVSPEC decltype(std::declval<CLASS_NAME>().FIELD_SPEC) *fldPtr) ->
CVSPEC CLASS_NAME * { \
return reinterpret_cast<CVSPEC CLASS_NAME *>(reinterpret_cast<CVSPEC
char *>(fldPtr) - offsetof(CLASS_NAME, FIELD_SPEC)); \
}(FIELD_PTR))
/*
NOTE: this is generalizing the technique of static_cast'ing from a base
class pointer to a derived class pointer. It
allows this technique with class fields as well as base classes. But it's
easy to make a mistake that the compiler
would not catch unfortunately, must be used very carefully. The lambda
function is used so that at least the compiler
can check that the type of the pointer and the type of the class field
match.
*/
This technique is not strictly necessary, but I have found many cases where
I felt using it made the code clearer and more concise.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fa582cd9-7a72-4151-821f-d1c095303bf3%40isocpp.org.
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fa582cd9-7a72-4151-821f-d1c095303bf3%40isocpp.org.