A problem about template?

Discussion in 'C++' started by Wayne Shu, Mar 6, 2007.

  1. Wayne Shu

    Wayne Shu Guest

    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??
     
    Wayne Shu, Mar 6, 2007
    #1
    1. Advertising

  2. Wayne Shu

    Sarath Guest

    On Mar 6, 6:16 pm, "Wayne Shu" <> wrote:
    > 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.
     
    Sarath, Mar 6, 2007
    #2
    1. Advertising

  3. Sarath wrote:
    > On Mar 6, 6:16 pm, "Wayne Shu" <> wrote:
    >>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
     
    Stuart Redmann, Mar 6, 2007
    #3
  4. Wayne Shu

    Wayne Shu Guest

    On 3ÔÂ6ÈÕ, ÏÂÎç7ʱ56·Ö, Stuart Redmann <> wrote:
    > Sarath wrote:
    > > On Mar 6, 6:16 pm, "Wayne Shu" <> wrote:
    > >>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 };
    If I delete "IsClassT<T>::" in this statement, it can be compiled in
    vc8 and gcc too.

    > Regards,
    > Stuart- Òþ²Ø±»ÒýÓÃÎÄ×Ö -
    >
    > - ÏÔʾÒýÓõÄÎÄ×Ö -


    Regards.
     
    Wayne Shu, Mar 6, 2007
    #4
  5. >>>On Mar 6, 6:16 pm, "Wayne Shu" <> wrote:
    >>>>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 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
     
    Stuart Redmann, Mar 6, 2007
    #5
  6. Wayne Shu

    Guest

    On Mar 6, 1:16 am, "Wayne Shu" <> wrote:
    > 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.
     
    , Mar 6, 2007
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Theis
    Replies:
    2
    Views:
    475
    Chris Theis
    Jul 24, 2003
  2. tom_usenet
    Replies:
    0
    Views:
    537
    tom_usenet
    Jul 24, 2003
  3. Replies:
    1
    Views:
    2,112
    Gianni Mariani
    Jun 8, 2007
  4. Peng Yu
    Replies:
    3
    Views:
    779
    Thomas J. Gritzan
    Oct 26, 2008
  5. nguillot
    Replies:
    5
    Views:
    532
Loading...

Share This Page