469,927 Members | 1,273 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,927 developers. It's quick & easy.

A problem about template?

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 Cstatic One test(int C::*);
template<typename Cstatic 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??

Mar 6 '07 #1
5 2312
On Mar 6, 6:16 pm, "Wayne Shu" <Wayne...@gmail.comwrote:
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 Cstatic One test(int C::*);
template<typename Cstatic 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.

Mar 6 '07 #2
Sarath wrote:
On Mar 6, 6:16 pm, "Wayne Shu" <Wayne...@gmail.comwrote:
>>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 Cstatic One test(int C::*);
template<typename Cstatic 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
Mar 6 '07 #3
On 3月6日, 下午7时56分, Stuart Redmann <DerTop...@web.dewrote:
Sarath wrote:
On Mar 6, 6:16 pm, "Wayne Shu" <Wayne...@gmail.comwrote:
>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 Cstatic One test(int C::*);
template<typename Cstatic 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 };
If I delete "IsClassT<T>::" in this statement, it can be compiled in
vc8 and gcc too.
Regards,
Stuart- 隐藏被引用文字 -

- 显示引用的文字 -
Regards.

Mar 6 '07 #4
>>>On Mar 6, 6:16 pm, "Wayne Shu" <Wayne...@gmail.comwrote:
>>>>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 Cstatic One test(int C::*);
template<typename Cstatic 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 Shu wrote:
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
Mar 6 '07 #5
On Mar 6, 1:16 am, "Wayne Shu" <Wayne...@gmail.comwrote:
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 Cstatic One test(int C::*);
template<typename Cstatic 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.

Mar 6 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by CoolPint | last post: by
5 posts views Thread by Tony Johansson | last post: by
1 post views Thread by suzy | last post: by
8 posts views Thread by sagi.perel | last post: by
4 posts views Thread by StephQ | last post: by
17 posts views Thread by JohnQ | last post: by
4 posts views Thread by parag_paul | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.