"has member" detection using templates - why "." operator fails ?

G

Gianni Mariani

I'm hoping someone can tell me why using member address of works and why
using the dot operator does not in the code below.

The code below uses the template function resolution mechanism to
determine wether a class contains a member. My understanding is that if
a template function has an error during resolution of the function
types, it is quietly eliminated from the resolution process. This can
be used to detect things that would normally be an error to detect in
regular code, namely checking for existance of a member. To get this
mechanism to work, you need to contrive a class where you force the
compiler at compile time to resolve which function to use but never
actually call the function - sizeof comes to the aid. Each of the
functions used can return a different sized object and the selection can
proceed based on the size of the object that would be returned.

So far so good.

In my last attempt to do this, I noticed that no matter what I did, when
I attempted to use the "." operator, the error was not silent. GCC as
well as Comeau's try it out were not silent about function template
resolution error when a "." operator was involved. However, taking the
sizeof a pointer to member works as expected.

The code is below. As posted it compiles under GCC (and I suspect
comeau). I have not tested this on MSVC but if my experience a while
back is any indication, it probably does not compile indicating a bug in
MSVC.

Why does the "." operator fail to compile in this case and the &T::
succeed ?


struct NoMemb { char a[1]; };
struct Memb_MemberA { char a[2]; };
struct Memb_MemberB { char a[3]; };

template <typename T>
struct InitObject
{
private:

struct xA {};
struct xB : xA {};

template <int w_size>
struct Detect
{
};

public:

// detect using sizeof( &T::membername )
template <typename U>
inline static Memb_MemberB ObjInitSel(
U & obj, xB * b, Detect< sizeof(&U::MemberB) > * = 0
);

template <typename U>
inline static Memb_MemberA ObjInitSel(
U & obj, xB * b, Detect< sizeof(&U::MemberA) > * = 0
);

template <typename U>
inline static NoMemb ObjInitSel( U & obj, xA * a );


// detect using sizeof( T().membername )
template <typename U>
inline static Memb_MemberB ObjInitSelDot(
U & obj, xB * b, Detect< sizeof(U().MemberB) > * = 0
);

template <typename U>
inline static Memb_MemberA ObjInitSelDot(
U & obj, xB * b, Detect< sizeof(U().MemberA) > * = 0
);

template <typename U>
inline static NoMemb ObjInitSelDot( U & obj, xA * a );


inline int ObjTest()
{
typedef xB * bp;

T obj = T();

int a = sizeof( ObjInitSel( obj, bp() ) );

// uncomment line below to show the error using "."
// a += sizeof( ObjInitSelDot( obj, bp() ) );

return a;
}
};



/////////// test code

struct A
{
int a;
char x[10];
};


struct B
{
int MemberA;
char x[15];
};


struct C
{
int MemberB;
char x[22];
};

int main()
{
InitObject<A>().ObjTest();
InitObject<B>().ObjTest();
InitObject<C>().ObjTest();
}
 
A

Alf P. Steinbach

* Gianni Mariani:
I'm hoping someone can tell me why using member address of works and why
using the dot operator does not in the code below.

The code below uses the template function resolution mechanism to
determine wether a class contains a member. My understanding is that if
a template function has an error during resolution of the function
types, it is quietly eliminated from the resolution process. This can
be used to detect things that would normally be an error to detect in
regular code, namely checking for existance of a member. To get this
mechanism to work, you need to contrive a class where you force the
compiler at compile time to resolve which function to use but never
actually call the function - sizeof comes to the aid. Each of the
functions used can return a different sized object and the selection can
proceed based on the size of the object that would be returned.

So far so good.

In my last attempt to do this, I noticed that no matter what I did, when
I attempted to use the "." operator, the error was not silent. GCC as
well as Comeau's try it out were not silent about function template
resolution error when a "." operator was involved. However, taking the
sizeof a pointer to member works as expected.

The code is below. As posted it compiles under GCC (and I suspect
comeau). I have not tested this on MSVC but if my experience a while
back is any indication, it probably does not compile indicating a bug in
MSVC.

With MSVC 7.1 moving the Detect structure to global scope helps a lot,
but not for the ".".

Why does the "." operator fail to compile in this case and the &T::
succeed ?

Compiles fine with Comeau Online. ;-)

However, not with g++ 3.4.4 under Windows XP, and furthermore, changing
"U().Method" to "((U*)0)->Method" ICEs the compiler:

vc_project.cpp: In instantiation of `InitObject<A>':
vc_project.cpp:91: instantiated from here
vc_project.cpp:39: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://www.mingw.org/bugs.shtml> for instructions.

I suggest you submit a full bug report.

[code, snipped]
 
G

Gianni Mariani

Alf P. Steinbach wrote:
....
Compiles fine with Comeau Online. ;-)

However, not with g++ 3.4.4 under Windows XP, and furthermore, changing
"U().Method" to "((U*)0)->Method" ICEs the compiler:

vc_project.cpp: In instantiation of `InitObject<A>':
vc_project.cpp:91: instantiated from here
vc_project.cpp:39: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://www.mingw.org/bugs.shtml> for instructions.

I suggest you submit a full bug report.

It does not ICE on g++ 4.1.1. (does ICE on g++ 4.0.0)

It does compile fine with comeau. It looks like it's a bug in gcc.
 
R

Ron Natalie

Alf said:
However, not with g++ 3.4.4 under Windows XP, and furthermore, changing
"U().Method" to "((U*)0)->Method" ICEs the compiler:
While I'm sure that's not what the GCC guys intended, an internal
compiler error is a valid response to invocation of undefined
behavior :)
 
A

Alf P. Steinbach

* Ron Natalie:
While I'm sure that's not what the GCC guys intended, an internal
compiler error is a valid response to invocation of undefined
behavior :)

Well, it's within a sizeof. But I agree that a case can be made that
it's still UB. I've tried to make that case (didn't convince many).
 

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,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top