about SFINAE usage

F

feverzsj

i wrote a template to test whether a type is a class type.
but i find that using an ordinary member function "test()" will cause
compiler error like"no qualified name for pointer to member".
what's the difference in this place???


template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum{YES = sizeof(test<T>(0))==1};
enum{NO = !YES};
};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class type"<<endl;
}
 
V

Victor Bazarov

feverzsj said:
i wrote a template to test whether a type is a class type.
but i find that using an ordinary member function "test()"

What's "ordinary" in this case? How are you "using" that function?
> will cause
compiler error like"no qualified name for pointer to member".
what's the difference in this place???

If you want to know about the differences between two pieces of code,
post both pieces of code and the exact compiler diagnostic, not "like".

See FAQ 5.8.
template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum{YES = sizeof(test<T>(0))==1};
enum{NO = !YES};
};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class type"<<endl;
}

V
 
A

Alf P. Steinbach

* feverzsj:
i wrote a template to test whether a type is a class type.
but i find that using an ordinary member function "test()" will cause
compiler error like"no qualified name for pointer to member".
what's the difference in this place???


template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum{YES = sizeof(test<T>(0))==1};
enum{NO = !YES};
};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class type"<<endl;
}

How come so many of you moro^H^H^H^Hnewbies think that C++ programmers who would
help you out, must be telepathic?

Anyways, here's the scoop, the absolutely mind-boggling amazing unbelievable
fact: there isn't any telepathy or other ESP powers involved in C++ programming.

Show the f***ing code that doesn't compile.


Grumble, grumble,

- Alf

PS: By the way, don't use all uppercase for non-macros. You could also greatly
improve the name of ClassChecker. E.g. IsClass.
 
F

feverzsj

my apology for all these confused stuff...
this is an example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.
anyway the error code is as below:

template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
static One test(int C::*); // an ordinary member function
instead of member template
static Two test(...); // **
public:
enum{YES = sizeof(test(0))==1}; //**
enum{NO = !YES};

};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class
type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class
type"<<endl;

}

and the compiler[vc9] gives:" ...error C2645: no qualified name for
pointer to member (found ':: *')..."
 
V

Vladimir Jovic

feverzsj said:
my apology for all these confused stuff...
this is an example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.
anyway the error code is as below:

template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
static One test(int C::*); // an ordinary member function
instead of member template
static Two test(...); // **
public:
enum{YES = sizeof(test(0))==1}; //**
enum{NO = !YES};

};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class
type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class
type"<<endl;

}

and the compiler[vc9] gives:" ...error C2645: no qualified name for
pointer to member (found ':: *')..."


Must be a compiler bug. Compiling with g++ (v 4.3.0), I am getting these:
g++ rh.cpp
rh.cpp:17:43: warning: missing terminating " character
rh.cpp:17: error: missing terminating " character
rh.cpp:18:13: warning: missing terminating " character
rh.cpp:18: error: missing terminating " character
rh.cpp:20:43: warning: missing terminating " character
rh.cpp:20: error: missing terminating " character
rh.cpp:21:13: warning: missing terminating " character
rh.cpp:21: error: missing terminating " character
rh.cpp:5: error: expected ‘,’ or ‘...’ before ‘::’ token
rh.cpp: In function ‘void CheckClass()’:
rh.cpp:17: error: ‘cout’ was not declared in this scope
rh.cpp:17: error: must #include <typeinfo> before using typeid
rh.cpp:18: error: ‘type’ was not declared in this scope
rh.cpp:19: error: expected `;' before ‘else’


I guess, you are missing main() and all includes.
However, this might help:
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8
 
A

Alf P. Steinbach

* feverzsj:
my apology for all these confused stuff...
this is an example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.
anyway the error code is as below:

template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
static One test(int C::*); // an ordinary member function
instead of member template
static Two test(...); // **
public:
enum{YES = sizeof(test(0))==1}; //**
enum{NO = !YES};

};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class
type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class
type"<<endl;

}

and the compiler[vc9] gives:" ...error C2645: no qualified name for
pointer to member (found ':: *')..."

Again you leave out the relevant information.

First, because the first message you get with your compiler is, I suspect,

error C2653: 'C' : is not a class or namespace name

unless you're compiling some code that's *different* from the one you posted,
which I would readily believe you're doing...

Second, because you don't supply the calling code, which is where you
instantiate ClassChecker with some non-class type, causing the error,.

Yeah, I know, sometimes one is just blind on both eyes, happens to everybody,
and has certainly happened enough times with me, but you really should make a
very strong effort to make sure that you supply the relevant information, and
that means, *not* applying preconceived ideas about what's relevant.

When you're asking for an explanation it's because you do not understand it at all.

So the assumption that you do understand enough to decide what's relevant is
unwarranted (I'd use stronger words but I already did and that's enough :) ).

Anyways, if you correct the code to use type T instead of undefined C, then when
instantiating ClassChecker with e.g. 'int' type T, then you have told the
compiler to instantiate the One version of 'test', which it can't do because
there's no such thing as e.g. 'int::*'. Without templating you do not have
SFINAE. With templating the compiler simply ignores the possible instantiation,
because that's what SFINAE is all about, ignoring possible instantiations.


Cheers & hth.,

- Alf


PS: Don't forget, when you *do not* understand something, don't assume that you
understand enough to decide that something is irrelevant. And please make sure
that the code you're compiling (and/or running) is the same as the posted code.
 
F

feverzsj

* feverzsj:


my apology for all these confused stuff...
this is an example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.
anyway the error code is as below:
template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
static One test(int C::*); // an ordinary member function
instead of member template
static Two test(...); // **
public:
enum{YES = sizeof(test(0))==1}; //**
enum{NO = !YES};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class
type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class
type"<<endl;

and the compiler[vc9] gives:" ...error C2645: no qualified name for
pointer to member (found ':: *')..."

Again you leave out the relevant information.

First, because the first message you get with your compiler is, I suspect,

error C2653: 'C' : is not a class or namespace name

unless you're compiling some code that's *different* from the one you posted,
which I would readily believe you're doing...

Second, because you don't supply the calling code, which is where you
instantiate ClassChecker with some non-class type, causing the error,.

Yeah, I know, sometimes one is just blind on both eyes, happens to everybody,
and has certainly happened enough times with me, but you really should make a
very strong effort to make sure that you supply the relevant information, and
that means, *not* applying preconceived ideas about what's relevant.

When you're asking for an explanation it's because you do not understand it at all.

So the assumption that you do understand enough to decide what's relevant is
unwarranted (I'd use stronger words but I already did and that's enough :) ).

Anyways, if you correct the code to use type T instead of undefined C, then when
instantiating ClassChecker with e.g. 'int' type T, then you have told the
compiler to instantiate the One version of 'test', which it can't do because
there's no such thing as e.g. 'int::*'. Without templating you do not have
SFINAE. With templating the compiler simply ignores the possible instantiation,
because that's what SFINAE is all about, ignoring possible instantiations..

Cheers & hth.,

- Alf

PS: Don't forget, when you *do not* understand something, don't assume that you
understand enough to decide that something is irrelevant. And please make sure
that the code you're compiling (and/or running) is the same as the posted code.

thanks for your reply!
and also appreciate the suggestion.

do you mean: 1. common members defined in a class template r not
templates
2 only template can benefit from the SFINAE
 
S

SG

my apology for all these confused stuff...
this is an example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.
anyway the error code is as below:

template<typename T>
class ClassChecker{
    typedef char One;
    typedef struct{char _c[2];} Two;
    static One test(int C::*);  // no template
    static Two test(...);      // no template

So? What exactly are you asking? Did you mean to write

static One test(int T::*); // T instead of C

(because the compiler doesn't know what C is supposed to be)?

As far as I can tell it still won't work because it isn't a template
anymore. Did you mean to ask why both test functions need to be
templates? If yes, isn't this covered in your book already?

Cheers!
SG
 
A

Alf P. Steinbach

* feverzsj:
do you mean: 1. common members defined in a class template r not
templates

Please don't post with Chinese character encoding, because my Thunderbird (and
everone else's Thunderbird) then uses a horrible font.

Anyway, no I don't mean that, and "common member" is not exactly clear even as a
descriptive term.

A non-template routine can be part of a template, but it's not a template on its
own.

2 only template can benefit from the SFINAE

Considering that SFINAE is about the compiler ignoring (im)possible template
instantiations, what do you think?


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Jeff Schwab:
Speak for yourself. My copy of Thunderbird does not use a horrible
font, nor do I mind the GB2312 encoding.

Bah, egoist.


Cheers,

- Alf
 
F

feverzsj

* feverzsj:




Please don't post with Chinese character encoding, because my Thunderbird (and
everone else's Thunderbird) then uses a horrible font.

Anyway, no I don't mean that, and "common member" is not exactly clear even as a
descriptive term.

A non-template routine can be part of a template, but it's not a template on its
own.


Considering that SFINAE is about the compiler ignoring (im)possible template
instantiations, what do you think?

Cheers & hth.,

- Alf

--
Due to hosting requirements I need visits to <url:http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :) Just going there is good. Linking
to it is even better! Thanks in advance!

Anyway, no I don't mean that, and "common member" is not exactly clear even as a
descriptive term.

A non-template routine can be part of a template, but it's not a template on its
own.

a common member( have no idea about the exact term ) within a class
template rely on template parameters is non-template?
and for my encoding , i think i'm using utf-8 on my firefox3
 
A

Alf P. Steinbach

* feverzsj:
Please don't quote signatures.

a common member( have no idea about the exact term ) within a class
template rely on template parameters is non-template?

Yes, when the containing template is instatiated you have a concrete class at
hand, and any actually used non-template members are then very much real.

But the "actually used" means that the issue is subtle.

For example, the following is fine, standard conforming C++:

template< typename T >
struct Foo
{
void ungoodIfEverCalled()
{
T().poi(); // Very ungood for T=int.
}

void bar()
{
}
};

int main()
{
Foo<int>().bar(); // OK.
}

ungoodIfEverCalled is not a template, but since it's a separate part of a
template it's not created unless it's referenced, which it isn't.

This might seem to be similar to SFINAE, but it isn't.

For the incorrect code in ungoodIfEverCalled doesn't matter to the compiler at
all and is not the reason that ungoodIfEverCalled isn't "compiled": the reason
is that it's a part of a template and isn't referenced or used in any way.


and for my encoding , i think i'm using utf-8 on my firefox3

Oh, it's (probably) Google Groups screwing up things.

Consider using a real newsreader instead of Google Groups.


Cheers & hth.,

- Alf
 
J

James Kanze

my apology for all these confused stuff... this is an
example from [C++ Templates: The Complete Guide],which i
thought should be typical enough. anyway the error code is
as below:
template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
static One test(int C::*); // no template
static Two test(...); // no template
So? What exactly are you asking? Did you mean to write
static One test(int T::*); // T instead of C
(because the compiler doesn't know what C is supposed to be)?

More likely he meant to write:
As far as I can tell it still won't work because it isn't a
template anymore. Did you mean to ask why both test functions
need to be templates? If yes, isn't this covered in your book
already?

Are you sure the second one must be a template. I don't think
it can be---type deduction won't work for matching ...
 
S

SG

my apology for all these confused stuff...  this is an
example from [C++ Templates: The Complete Guide],which i
thought should be typical enough.  anyway the error code is
as below:
template<typename T>
class ClassChecker{
    typedef char One;
    typedef struct{char _c[2];} Two;
    static One test(int C::*);  // no template
    static Two test(...);       // no template
So? What exactly are you asking? Did you mean to write
      static One test(int T::*);  // T instead of C
(because the compiler doesn't know what C is supposed to be)?

More likely he meant to write:
    template< typename C >
    static One test( int C::* ) ;

I don't think he did. His first example used member templates and his
second example seemed to purposefully lack member templates. From what
I can tell he meant to ask why his 2nd version doesn't work while the
first one does (yes, it works, actually).
Are you sure the second one must be a template.  I don't think
it can be---type deduction won't work for matching ...

Type deduction won't even work for the first function. And it doesn't
have to. The very first example included the following line:

enum{YES = sizeof(test<T>(0))==1};

in which the template parameter is given explicitly. So, the 2nd
function has to be a template as well. Also, a non-templated function
with an ellipsis is still a "better function" (w.r.t. overload
resolution) than a function template template in case both are viable.

Cheers!
SG
 
N

Noah Roberts

feverzsj said:
i wrote a template to test whether a type is a class type.
but i find that using an ordinary member function "test()" will cause
compiler error like"no qualified name for pointer to member".
what's the difference in this place???


template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum{YES = sizeof(test<T>(0))==1};
enum{NO = !YES};
};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class type"<<endl;
}

You really do need to supply the calling code because the above worked
just fine for me once I supplied a couple classes and called CheckClass():


struct X
{
int f() { return 5; }
};

struct Y { void f() {} };

struct Z {};

union WTF { int x; double z; };

int main()
{
CheckClass<Y>();
CheckClass<X>();
CheckClass<Z>();
CheckClass<int>();
CheckClass<WTF>();

cin.get();
}

type 'struct Y' IS a Class type
type 'struct X' IS a Class type
type 'struct Z' IS a Class type
type 'int' IS NOT a Class type
type 'union WTF' IS a Class type

Note the last bit there. It seems that the code is actually totally
inadequate for telling if a type is a class or not.

MSVC 8.0
 
V

Victor Bazarov

Noah said:
feverzsj said:
i wrote a template to test whether a type is a class type.
but i find that using an ordinary member function "test()" will cause
compiler error like"no qualified name for pointer to member".
what's the difference in this place???


template<typename T>
class ClassChecker{
typedef char One;
typedef struct{char _c[2];} Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum{YES = sizeof(test<T>(0))==1};
enum{NO = !YES};
};

template<typename T>
void CheckClass()
{
if( ClassChecker<T>::YES )
cout<<"type '"<<typeid(T).name()<<"' IS a Class type"<<endl;
else
cout<<"type '"<<typeid(T).name()<<"' IS NOT a Class type"<<endl;
}

You really do need to supply the calling code because the above worked
just fine for me once I supplied a couple classes and called CheckClass():


struct X
{
int f() { return 5; }
};

struct Y { void f() {} };

struct Z {};

union WTF { int x; double z; };

int main()
{
CheckClass<Y>();
CheckClass<X>();
CheckClass<Z>();
CheckClass<int>();
CheckClass<WTF>();

cin.get();
}

type 'struct Y' IS a Class type
type 'struct X' IS a Class type
type 'struct Z' IS a Class type
type 'int' IS NOT a Class type
type 'union WTF' IS a Class type

Note the last bit there. It seems that the code is actually totally
inadequate for telling if a type is a class or not.

Why do you say that it is inadequate? Is union not a class? Can it not
have members? Can it not have the address of a member taken and
converted to a pointer-to-member? What *make* a class, in your opinion?
Does it have to be defined/declared with the keyword 'class'? For
references, see 9/1.

V
 

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,769
Messages
2,569,582
Members
45,061
Latest member
KetonaraKeto

Latest Threads

Top