A problem about template?

W

Wayne Shu

Hi, guys

I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.

When I read the chapter 15: Traits and Policy classes.

I copy the code in 15.2.2 that use to determining the class type.

The code is below:
#include <iostream>

template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};

struct MyStruct{};
union MyUnion{};

int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;
}

It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(65) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(66) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>Build log was saved at "file://d:\code\vc8_debug\sample\Debug
\BuildLog.htm"
1>sample - 6 error(s), 0 warning(s)

Why it can't be compiled using vc8 and gcc??
 
S

Sarath

Hi, guys

I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.

When I read the chapter 15: Traits and Policy classes.

I copy the code in 15.2.2 that use to determining the class type.

The code is below:
#include <iostream>

template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };

};

struct MyStruct{};
union MyUnion{};

int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;

}

It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(65) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(66) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>Build log was saved at "file://d:\code\vc8_debug\sample\Debug
\BuildLog.htm"
1>sample - 6 error(s), 0 warning(s)

Why it can't be compiled using vc8 and gcc??

For me the code looks with some strange logic.
C2783 error is because of the compiler cannot determine a template
argument.

AFAIK, enumerations are defined at compile time and also sizeof of
operator is valid only at compile time. not at runtime.

sizeof(fxn(0));
the above statement is neither making a function call nor validating
the size of return value. I dont know why sizeof returns '0' in this
case, but in the case of an empty class or structure, sizeof operator
returns 1 to avoid some unexpecte behavior that can be occured because
of returning size as 0. e.g is if we are declaring an array of empty
class, it should not be 0 right?

To verify that sizeof(fxn(0)); not making a function call, just
declare the function without defining its body. The linker will not
throw any linker error (even with your code if we make it compilable)
because the function call not happening anywhere. From this we can
veryfiy that there's nothing happening with such type of expression.
even if you define the body it will not be called.

There's another great example from Effective C++ that "Never re-define
the default paramemeter of a virtual funciton in the derived class.

e.g

class Base
{
public:
virtual void Test(COLOR c = RED); // Assume RED nad GREEN are
enumerations
};

class Derived: public Base
{
public:
void Test(COLOR c = GREEN)
}


What's the error in the above code is that you are creating a an
derived class object using base class pointer,

Base* p = new Derived;
p->Test();

when the compiler see the above, code it will replace the deafult
parameter with base class's value since the parameter defaulting is
doing at compiler time. this can cause some unexpected result.

So always differentiate between compile time and runtime operators.
 
S

Stuart Redmann

Sarath said:
I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.
I copy the code in 15.2.2 that use to determining the class type.
#include <iostream>

template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };

};

struct MyStruct{};
union MyUnion{};

int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;

}

It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]

[snipped rest of error message]
For me the code looks with some strange logic.
C2783 error is because of the compiler cannot determine a template
argument.

AFAIK, enumerations are defined at compile time and also sizeof of
operator is valid only at compile time. not at runtime.
Right.

sizeof(fxn(0));
the above statement is neither making a function call nor validating
the size of return value. I dont know why sizeof returns '0' in this
case, but in the case of an empty class or structure, sizeof operator
returns 1 to avoid some unexpecte behavior that can be occured because
of returning size as 0. e.g is if we are declaring an array of empty
class, it should not be 0 right?

What should happen here is the following: The compiler sees a function
call to an un-qualified function called "fxn". There are two functions
that can be used for this:
IsClassT<MyStruct>::test<MyStruct>(int MyStruct::*) and
IsClassT<MyStruct>::test<MyStruct>(...)
Since MyStruct is a class, it is possible to cast the argument, "0" to
the type "int MyStruct::*", meaning a pointer to an int member of
MyStruct. This way both methods are considered as possible targets for
the name "fxn", so the compiler chooses the first one (as the compiler
will regard functions with ellipses always as last choice). Note that if
you pass a non-class argument into IsClassT, the first function cannot
be used and SFINAE cuts in.

Just a guess: Did you try to turn off Microsoft Extensions for the
compiling settings (I heard some rumours that those are in conflict with
some of the fancy template tricks that are used by boost, so this may
apply in your case as well).

Regards,
Stuart
 
W

Wayne Shu

Sarath said:
I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.
I copy the code in 15.2.2 that use to determining the class type.
#include <iostream>
template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
struct MyStruct{};
union MyUnion{};
int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;
}
It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]

[snipped rest of error message]
For me the code looks with some strange logic.
C2783 error is because of the compiler cannot determine a template
argument.
AFAIK, enumerations are defined at compile time and also sizeof of
operator is valid only at compile time. not at runtime.
Right.

sizeof(fxn(0));
the above statement is neither making a function call nor validating
the size of return value. I dont know why sizeof returns '0' in this
case, but in the case of an empty class or structure, sizeof operator
returns 1 to avoid some unexpecte behavior that can be occured because
of returning size as 0. e.g is if we are declaring an array of empty
class, it should not be 0 right?

What should happen here is the following: The compiler sees a function
call to an un-qualified function called "fxn". There are two functions
that can be used for this:
IsClassT<MyStruct>::test<MyStruct>(int MyStruct::*) and
IsClassT<MyStruct>::test<MyStruct>(...)
Since MyStruct is a class, it is possible to cast the argument, "0" to
the type "int MyStruct::*", meaning a pointer to an int member of
MyStruct. This way both methods are considered as possible targets for
the name "fxn", so the compiler chooses the first one (as the compiler
will regard functions with ellipses always as last choice). Note that if
you pass a non-class argument into IsClassT, the first function cannot
be used and SFINAE cuts in.

Just a guess: Did you try to turn off Microsoft Extensions for the
compiling settings (I heard some rumours that those are in conflict with
some of the fancy template tricks that are used by boost, so this may
apply in your case as well).
I have tried to compiled with turning off the language extensions be
turned off.
The same result.
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
Regards,
Stuart- Òþ²Ø±»ÒýÓÃÎÄ×Ö -

- ÏÔʾÒýÓõÄÎÄ×Ö -

Regards.
 
S

Stuart Redmann

I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.
I copy the code in 15.2.2 that use to determining the class type.
#include <iostream>
template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };

struct MyStruct{};
union MyUnion{};
int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;

It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]

Wayne said:
I have tried to compiled with turning off the language extensions be
turned off.
The same result.
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
If I delete "IsClassT<T>::" in this statement, it can be compiled in
vc8 and gcc too.

That's contrary to common sense, as the compiler will definitely not
gain any information about the template argument "C" if you leave out
the class scope. It looks like a compiler bug to me (there are certainly
a lot of errors in both Microsoft and Gnu compilers, so I'd rather trust
Comeau).

Stuart
 
A

amparikh

Hi, guys

I am reading Vandevoorde and Josuttis 's "C++ Template The Complete
Guide" these days.

When I read the chapter 15: Traits and Policy classes.

I copy the code in 15.2.2 that use to determining the class type.

The code is below:
#include <iostream>

template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };

};

struct MyStruct{};
union MyUnion{};

int main()
{
std::cout << IsClassT<MyStruct>::Yes << std::endl
<< IsClassT<MyUnion>::Yes << std::endl;
return 0;

}

It can be compiled using the Comeau C/C++ 4.3.8 for ONLINE_EVALUATION
but it can't be compiled using the MS VC 8 and gcc version 3.4.2
(mingw-special)
the error message is:
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(65) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyStruct
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyStruct
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2783:
'IsClassT<T>::Two IsClassT<T>::test(...)' : could not deduce template
argument for 'C'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(54) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(66) : see reference to
class template instantiation 'IsClassT<T>' being compiled
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2784:
'IsClassT<T>::One IsClassT<T>::test(int C::* )' : could not deduce
template argument for 'int C::* ' from 'int'
1> with
1> [
1> T=MyUnion
1> ]
1> d:\code\vc8_debug\sample\main.cpp(53) : see declaration of
'IsClassT<T>::test'
1> with
1> [
1> T=MyUnion
1> ]
1>d:\code\vc8_debug\sample\main.cpp(56) : error C2056: illegal
expression
1>Build log was saved at "file://d:\code\vc8_debug\sample\Debug
\BuildLog.htm"
1>sample - 6 error(s), 0 warning(s)

Why it can't be compiled using vc8 and gcc??


There are some bugs with vc8 when using SFINAE techniques. I had
myself entered one sometime back and there were some entered by others
too.
Just do a search on the vstudio site.
 

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,774
Messages
2,569,596
Members
45,130
Latest member
MitchellTe
Top