Thread: Undefined reference - however they ARE defined

  1. #1
    Registered User
    Join Date
    May 2008
    Posts
    21

    Undefined reference - however they ARE defined

    I'm having an odd problem with my code. I have a template function in my class.
    This is in the header file lcmp.h as so:
    Code:
    class LCMPMsg{
        public:
            ...
            template <class T> T* getField(const char* name);
            ...
    };
    I then have the implementation of this function in lcmp.cpp ...
    Code:
    template <class T>
    T* LCMPMsg::getField(const char* name){
    	LCMPMsgFieldIt i = _findField(name);
    	if(i != _fields.end()){
    		return (T*)(*i).data;		
    	}
    	return 0;
    }
    Yet, I receive undefined reference to <T> at compile time - T being whatever type I've used in the call.. for example:
    Code:
    if(msg->fieldExists("string")){
        std::cout << "String: " << msg->getField<char>("string") << "\n";
    }
    So I receive undefined reference to `char* LCMPMessage::getField<char>(char const*)' ... But oddly not a single undefined reference to ANY of the other functions in the lcmp.cpp - including the template setField() function nor _setField() which is also a template function:
    Code:
    template <typename T>
    void LCMPMsg::setField(const char* name, T value){
        int size = sizeof(T);
        _setField(name, reinterpret_cast<const unsigned char*>(&value), size);
    }
    If I copy the getField() code directly into the file I'm using it in, it works just fine. How can all of the other functions be picked up but my getField() it's quite confusing.

    I'm using the GCC compiler... Here's the console dump:
    Code:
    **** Build of configuration Debug for project gsocket ****
    
    make -k all 
    Building file: ../main.cpp
    Invoking: GCC C++ Compiler
    g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o"main.o" "../main.cpp"
    Finished building: ../main.cpp
     
    Building target: gsocket
    Invoking: GCC C++ Linker
    g++  -o"gsocket"  ./gsocket.o ./main.o  ./lcmp/lcmp.o   
    ./main.o: In function `main':
    /home/michael/projects/gsocket/Debug/../main.cpp:42: undefined reference to `char* LCMPMsg::getField<char>(char const*)'
    /home/michael/projects/gsocket/Debug/../main.cpp:45: undefined reference to `float* LCMPMsg::getField<float>(char const*)'
    /home/michael/projects/gsocket/Debug/../main.cpp:48: undefined reference to `double* LCMPMsg::getField<double>(char const*)'
    collect2: ld returned 1 exit status
    make: *** [gsocket] Error 1
    make: Target `all' not remade because of errors.
    Build complete for project gsocket

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You must define your template class functions in a header-file (or technically, in the same compile unit - so the whole function needs to be known in the .cpp file that is being compiled at the moment).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    May 2008
    Posts
    21
    I see - so there's no RTTI involved with templates and an actual function matching the types I'm passing is created at compile time which all subsequent calls are then pointed to? So I only have to define the template function in the header - and the compiler will create these methods if it finds they're undefined when it's compiling a call to said method?

    If this is the case - and trying to separate design and implementation so to speak, it would work if I were to perhaps throw in some macro stuff to do this:
    Code:
    lcmp.h:
    
    class LCMPMsg{
        ....
    };
    
    #define LCMPMSG_TEMPLATE_FUNC
    #include "lcmp.cpp"
    #undef LCMPMSG_TEMPLATE_FUNC
    ...
    lcmp.cpp:
    
    #ifdef LCMPMSG_TEMPLATE_FUNC
    template <class T> T* LCMPMsg::getField(const char* name, T value){
        ....
    }
    #else
     ... other methods...
    #endif
    Is this a workable solution? Just so I can have that added separation of implementation?
    Last edited by scarecrow; 05-04-2008 at 04:44 AM.

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Possibly you don't need any trickery including the cpp file, it is just as good as if it was part of the header in the first place.
    You might also give the included file a different extension. Otherwise your IDE might decide that this file needs to be compiled, but you don't want that. It is just part of the header that is located in a different file.

    What is somewhat suspicious is whether you get anything good out of casting i->data into an arbitrary pointer...
    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).

  5. #5
    Registered User
    Join Date
    May 2008
    Posts
    21
    Actually I have rewritten it to return const T&, because it avoids problems in tracking data size of elements stored internally for one.

    Thanks for the heads up on the potential IDE problems - I like that idea so I'll probably go with that, seems somewhat more elegant.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. MinGW Linking GUI Program
    By Tonto in forum Tech Board
    Replies: 19
    Last Post: 08-23-2006, 03:28 PM
  3. Textbox
    By maxorator in forum Windows Programming
    Replies: 20
    Last Post: 09-25-2005, 10:04 AM
  4. DLL compiling question
    By Noose in forum Windows Programming
    Replies: 2
    Last Post: 12-16-2004, 07:16 AM
  5. compiler problem
    By sofarsoclose in forum C Programming
    Replies: 3
    Last Post: 07-10-2003, 11:39 AM