undefined reference to member function()

Whenever I compile my program, I get these list of errors:

main.cpp:23: undefined reference to `Map<int, int>::Map()'
main.cpp:24: undefined reference to `Map<int, int>::insert(int const&, int const&)'
main.cpp:26: undefined reference to `Map<int, int>::~Map()'
main.cpp:26: undefined reference to `Map<int, int>::~Map()'

But I can't figure out why it's not working. Is there something wrong with my Makefile?
(I didn't include the code for map.h + map.cpp because I don't think it's relevant to the problem. If it is, then I'll post it)

Makefile code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#Variables
COMPILE = g++
FLAGS = -g -W -Wall -Werror -ansi -pedantic
OBJS = map.o

#Targets

all: main.cpp $(OBJS)
	$(COMPILE) $(FLAGS) -o translate main.cpp $(OBJS)

map.o: map.cpp map.h
	$(COMPILE) $(FLAGS) -c map.cpp

clean:
	rm -rf *~ *.o translate


main function code:
1
2
3
4
5
6
7
8
9
10
11
12
#include "map.h"

using namespace std;

int main() {
    
    Map<int,int> test;
    test.insert(12, 12);

    return 0;

}
Last edited on
closed account (zb0S216C)
"Map" is neither a member of the "std" name-space nor is it defined elsewhere. Perhaps you're referring to "std::map"?

Wazzak
map is the AVL-tree based map I created, so map.h and map.cpp do exist.
Last edited on
closed account (zb0S216C)
Oh, OK. Are you template definitions within a .cpp file? If so, they shouldn't be there.

Wazzak
If you mean this by template definitions:
template <typename K, typename V>
Map<K, V>::somememberfunction()

then I have to keep it there or else it won't compile.
closed account (zb0S216C)
That's your problem, then. Template definitions cannot be placed within a source file, plain and simple. The reason behind it it simple: templates are not complete types until all template parameters have an associated argument. Until you instantiate your template class/function, it remains an incomplete type. Therefore, the compiler isn't able to compile the template definitions. Here's an example:

1
2
3
4
5
6
7
8
9
10
11
template< typename T >
class X
{
};

// "X" is an incomplete type because the value of "T" is unknown and the compiler needs this 
// information in order to complete the type.

X< int > Y;

// Here, you're giving the compiler the information it needs in order to complete "X" as a type. 

In short, template definitions must reside within a header file unless the class is explicitly instantiated to form a complete type, like this:

1
2
3
4
// Source.cpp
#include "map.h"

template class map< int, int >;

Another way to form a complete type is to completely specialise the class with specific, complete types, but this isn't always a viable option.

Wazzak
Last edited on
So how would I change my source file?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
template <typename K, typename V>
class Map
{
private:
    K key;
    V value;
    Map<K,V> *left, *right;

public:
    Map();
    Map(K,V);
    Map(const Map& m); //overloaded copy
    Map<K,V>& operator = (const Map& m); //overloaded assign
    ~Map(); //deconstructor
    // add the big 3 functions

    // IO ///////////////////////////////////////
    
    /*
    You will use the file format of the "Internet Dictionary Project"
    You can find details at: http://www.june29.com/idp/IDPfileformat.html
    */
    void loadFromFile(string file);
    void saveToFile(string file);
    // mutators /////////////////////////////////
    /* adds (K,V) into the map, overwriting the previous value if it exists */
    void insert (const K&, const V&);
    /* erases (K,V) from the map */
    void erase (const K&);
    /* erases all elements from the map */
    void clear();
    // accessors ////////////////////////////////
    /* returns the number of (K,V) pairs stored in the map */
    int size() const;
    /* returns the height of the tree */
    int height() const;
    /* returns the tree's balance factor */
    int balanceFactor() const;
    /* return true if K is a valid key, false otherwise */
    bool isMember (const K&);        
    /* returns the V associated with K; if K is not a valid key, then print an error and abort the program */
    V lookup (const K&) const;
    /* returns the key that is most similar to the key passed in */
    K closestKey(const K&) const;
    /* returns the value of the key that is most similar to the key passed in.  Like lookup, but never aborts */
    V lookupSimilar (const K &k) const { return lookup(closestKey(k)); }
    //Map<K,V>&
    bool isBalanced();
    bool isValid();
    void swap(Map*&);
    void shiftLeft();
    void shiftRight();
    void balance();
    
};


I'm very confused on what I'm doing wrong (I barely know anything about templates).
Last edited on
You just copy it under the header file.
There is no source file with templates.
That is my header file.
@isn't source/header the same thing?
closed account (zb0S216C)
No. Source files are compiled, headers are not. It's common programming practice in C/C++ to place function prototypes in header files while placing the corresponding definition inside a source file so that the compiler can generate object code from it.

Wazzak
Last edited on
No. Source files are compiled, headers are not.

That's misleading. Header files are compiled as part of each and every source file that includes them.

Header files are not compiled independently of source files into their own object files, if that's what you meant.
closed account (zb0S216C)
Headers are copied into the translation unit, not moved, so they are -- in fact -- not compiled directly; thus, headers files are not compiled.

Wazzak
By default, in an IDE, a source file is a .CPP file, and a header file is a .H/.HPP file.

Their role in compilation is different.

A cpp file "translates" into an OBJ pre-executable file.
Multiple OBJ files "translate" into an executable file (Only if in one of the OBJ files, the Entry Point is defined, otherwise compilation errors occur).

Fact is, every function and class into a OBJ file must only be present ONCE.

You cannot define main twice, neither myfunction, unless it's an overload.

But, templates are an exception.
They must be in the header file as they MUST be SINGULARLY put into an OBJ file, otherwise.... Well, there's no way around that.

Headers file must contain declarations:
int function();
Source file must contain definitions:
int function() { return 1; }
Templates must be put into header files and must be fully defined:
1
2
int function();
template <typename T> void Test(T& t) { t.Test(); }
Topic archived. No new replies allowed.