Thread: Very smart compiler?

  1. #1
    Registered User
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    217

    Very smart compiler?

    Ok, this is going to be a bit hard to explain.

    I have two classes. Ones called CString and another is called CBuffer.
    CString has 5 constructors:
    Code:
        CString(const CString& pString);
        CString(const char* pString = "");
        CString(int pInteger);
        CString(float pFloat);
        CString(double pDouble);
    The first is a copy constructor, the second (default) is for copying a c-string into
    the string class and the last 3 convert numbers to a c-string than copy them
    into the string class.


    The CBuffer class has 4 constructors:

    Code:
    //Constructors
        CBuffer();
        CBuffer(const CBuffer& pBuffer);
        CBuffer(const CString& pString);
    
    //Template constructor
        template <class T> CBuffer(const T& pData);
    The first is a default constructor, the second is a copy constructor, the third is for
    copying a CString class and the fourth is a template constructor to copy simple data types
    such as int, float, doubles, structures, etc.

    CBuffer also has this:
    Code:
    CBuffer& operator=(const CBuffer& pData);
    Now i want to know how come when i do this:

    Code:
    CBuffer myBuff;
    myBuff = "Hello";
    It converts the const char* to a CString() (using the CString(const char*) constructor) than calls
    the CBuffer(const CString& pString) constructor to convert it to a CBuffer() object, THAN
    calls the "=" operator. WHICH IS WHAT I WANT.

    BUT when i do this:

    Code:
    CBuffer myBuff;
    myBuff = 1234;
    It does NOT convert the integer into a CString() than convert the CString() into a CBuffer() than
    pass the CBuffer() to the '=" operator. Instead it calls "template <class T> CBuffer(const T& pData);"
    and than passes the resulting CBuffer() into the "=" operator. WHICH IS WHAT I WANT.

    So although im not having any troubles, i just want to know how it knows to convert "const char*" to a
    CString() object but not an integer even though they both have constructors in the CString() object.
    The compiler is mingw.


    Hmm let me simplify it. How come CBuffer(32) calls the template constructor, while CBuffer("32") calls the
    CBuffer(const CString& pString); constructor even though CString() has a constructor for both of these datatypes?
    Last edited by 39ster; 01-08-2008 at 07:17 PM.

  2. #2
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    I'm not quite sure, but I think it has to do with the way it resolves types...

    What happens if you switch the order that your operator=() functions are declared?

  3. #3
    Registered User
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    217
    Actually its got little to do with the operator=(). Not sure why i mentioned it. You can get the same effect without using it like this:

    Code:
    CBuffer myBuff(32);
    CBuffer myBuff("32");
    First one calls the template constructor, second one calls the "CBuffer(const CString& pString)" constructor.
    The reason it calls the "CBuffer(const CString& pString)" is because CString() has a constructor for "const char*", but it also has a constructor for "int" so why does it do it differently.
    Last edited by 39ster; 01-08-2008 at 09:08 PM.

  4. #4
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    My WAG (and I've been out of C++ land for about 5 years now -- wow, time flies -- so take this with a grain of salt):

    The compiler is unwilling to make the assumption that 32 is an integer, as it could be unsigned or a long? What happens if you don't provide the template constructor? Does it not compile due to ambiguity? That's sort of what I'd expect.

  5. #5
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    It's because literal strings are treated as character arrays, so a literal string will prefer a template function over a const char *.

    There are two possible solutions: cast the string literal to a char * or write a template specialization for character arrays.

    The specialization will look something like this:
    Code:
    template <int I> CBuffer<char[I]>(char pString[I]);
    PS. Why do my I's get converted to lowercase?
    Last edited by King Mir; 01-08-2008 at 10:25 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Could you perhaps provide a compilable example and mention what compiler are you using?

    I ran this snippet and for me it calls the template constructor in both cases.
    Code:
    #include <iostream>
    using std::cout;
    
    class CString 
    {
        public:
        CString(unsigned ) { cout << "CString(unsigned)\n"; }
        CString(const char*) { cout << "CString(const char*)\n";}
    };
    
    class CBuffer
    {
        public:
        CBuffer(const CString&) { cout << "CBuffer(const CString&)\n";}
        template <class T>
        CBuffer(const T&) 
        { 
            cout << "CBuffer(const T&)\n";
        }
    };
    
    int main()
    {
        CBuffer a("hello world");
        CBuffer b(10u);
    }
    I thought the rule with templates was:
    1) If there is an exactly matching non-template version, use this
    2) else use the templated version (considering more specialized overloads first).

    In above code there is no exact match, so templated constructor is used. Even though there is a constructor for CString and CString has constructors for both const char* and unsigned I can't see how this could be considered an exact match and used over the templated version (although it gets used if the templated constructor is commented out).

    As to literal strings not matching to const char*, if that was so then both my MingW and Comeau online would have to be wrong, because they pick foo(const char*):
    Code:
    #include <iostream>
    #include <string>
    using std::cout;
    
    void foo(const char* p)
    {
        cout << "foo(const char*)\n" << p << "\n\n";
    }
    
    
    void foo(const std::string& s)
    {
        cout << "foo(const string&)\n" << s << "\n\n";
    }
    
    template <class T>
    void foo(const T& t)
    {
        cout << "template\n" << t << "\n\n"; 
        
        //this would create a compile error with Comeau online 
        //if this overload was used
        //int n = t * 2;   
    }
    
    int main()
    {
        foo("Hello world");
    }
    (If foo(const char*) is commented out, template overload is preferred to std::string version - because that is not an exact match.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. added start menu crashes game
    By avgprogamerjoe in forum Game Programming
    Replies: 6
    Last Post: 08-29-2007, 01:30 PM
  2. Compiler Paths...
    By Cobra in forum C++ Programming
    Replies: 5
    Last Post: 09-26-2006, 04:04 AM
  3. C Compiler and stuff
    By pal1ndr0me in forum C Programming
    Replies: 10
    Last Post: 07-21-2006, 11:07 AM
  4. I can't get this new compiler to work.
    By Loduwijk in forum C++ Programming
    Replies: 7
    Last Post: 03-29-2006, 06:42 AM
  5. how to call a compiler?
    By castlelight in forum C Programming
    Replies: 3
    Last Post: 11-22-2005, 11:28 AM