"undefined reference" link error in Makefile

This was running before I changed Row to a template class.
Now it gets this error:
>make
g++ -ggdb -Wall -std=c++11 -c ../../lib/ScanCode/Sa.cpp -o obj/Sa.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/ScanCode/Sb.cpp -o obj/Sb.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Key/Ke.cpp -o obj/Ke.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Row/RowBase.cpp -o obj/RowBase.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Row/Row.cpp -o obj/Row.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Matrix/MatrixA.cpp -o obj/MatrixA.o
g++ -ggdb -Wall -std=c++11 -c ../../lib/Keyboard/Keyboard.cpp -o obj/Keyboard.o
g++ -ggdb -Wall -std=c++11 -c keyboard1.cpp -o obj/keyboard1.o
g++ obj/Sa.o obj/Sb.o obj/Ke.o obj/RowBase.o obj/Row.o obj/MatrixA.o obj/Keyboar
d.o obj/keyboard1.o -o a.exe
obj/keyboard1.o:keyboard1.cpp:(.rdata$_ZTV3RowILi4EE[__ZTV3RowILi4EE]+0x8): unde
fined reference to `Row<4>::scan()'
collect2.exe: error: ld returned 1 exit status
make: *** [a.exe] Error 1


Makefile:
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
# Macros ****************************************************
COMPILER = g++ -ggdb -Wall -std=c++11 -c

OBJ = obj/Sa.o obj/Sb.o obj/Ke.o obj/RowBase.o obj/Row.o obj/MatrixA.o obj/Keyboard.o obj/keyboard1.o

KEYBOARD_PATH = ../../lib/Keyboard/

MATRIX_PATH = ../../lib/Matrix/
MAT_PARENT = $(MATRIX_PATH)Matrix.cpp $(MATRIX_PATH)Matrix.h

ROW_PATH = ../../lib/Row/

KEY_PATH = ../../lib/Key/
KEY_PARENT = $(KEY_PATH)Key.cpp $(KEY_PATH)Key.h

SC_PATH = ../../lib/ScanCode/
SC_PARENT = $(SC_PATH)ScanCode.cpp $(SC_PATH)ScanCode.h

# Targets ****************************************************
all: a.exe

# link object files
a.exe: $(OBJ)
	g++ $^ -o $@

# (obj file from previouse rule is needed, linker did not detect ScanCode change)
# keyboard1
obj/keyboard1.o: keyboard1.cpp obj/Keyboard.o
	$(COMPILER) keyboard1.cpp -o $@

# lib
obj/Keyboard.o: $(KEYBOARD_PATH)Keyboard.cpp $(KEYBOARD_PATH)Keyboard.h obj/MatrixA.o
	$(COMPILER) $(KEYBOARD_PATH)Keyboard.cpp -o $@

obj/MatrixA.o: $(MATRIX_PATH)MatrixA.cpp $(MATRIX_PATH)MatrixA.h $(MATRIX_PARTENT) obj/Row.o
	$(COMPILER) $(MATRIX_PATH)MatrixA.cpp -o $@

obj/Row.o: $(ROW_PATH)Row.cpp $(ROW_PATH)Row.h obj/RowBase.o obj/Ke.o
	$(COMPILER) $(ROW_PATH)Row.cpp -o $@

obj/RowBase.o: $(ROW_PATH)RowBase.cpp $(ROW_PATH)RowBase.h
	$(COMPILER) $(ROW_PATH)RowBase.cpp -o $@

obj/Ke.o: $(KEY_PATH)Ke.cpp $(KEY_PATH)Ke.h $(KEY_PARTENT)obj/Sa.o obj/Sb.o
	$(COMPILER) $(KEY_PATH)Ke.cpp -o $@

obj/Sb.o: $(SC_PATH)Sb.cpp $(SC_PATH)Sb.h $(SC_PARENT)
	$(COMPILER) $(SC_PATH)Sb.cpp -o $@

obj/Sa.o: $(SC_PATH)Sa.cpp $(SC_PATH)Sa.h $(SC_PARENT)
	$(COMPILER) $(SC_PATH)Sa.cpp -o $@

#clean
clean:
	rm $(OBJ)


Row.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef Row_h
#define Row_h
#include <iostream>
#include "RowBase.h"
#include "../Key/Key.h"

template< int sampleSize >
class Row : public RowBase
{
    private:
	Key*const *const ptrsKeys;		// row is composed of an array of Keys
	const int numCols;

	int samples[sampleSize];		// array size not specified
    public:
	//Row(Key*const pk[], const int nc): ptrsKeys(pk), numCols(nc) { }
	Row< sampleSize >(Key*const pk[], const int nc): ptrsKeys(pk), numCols(nc) { }
	void scan();
};
#endif 

Row.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Row.h"

template< int sampleSize >
void Row< sampleSize >::scan()
{
	for (int i=0; i<numCols; i++)
	{
		ptrsKeys[i]->press();
	}

	for (int j = 0; j < sampleSize; j++)	// traverse ring buffer
	{
		samples[j] = j;
		std::cout << samples[j];
	}
	std::cout << std::endl;
}

RowBase.h:
1
2
3
4
5
6
7
8
#ifndef RowBase_h
#define RowBase_h
class RowBase
{
	public:
		virtual void scan() = 0;
};
#endif 

RowBase.cpp:
1
2
#include "RowBase.h"
//empty file 


What is the source of the error?

Thank you.
you can't create an object ( Row.o ) out of a template. All of the code in Row.cpp needs to be moved to Row.h and then delete Row.cpp. Remove the compilation of Row.o from your makefile.
Lowest0ne,
That worked! C++ syntax/linker blows my mind again.
you can't create an object ( Row.o ) out of a template.

Thanks for your help.
I don't know much about it, but it does make sense to me. The template is just a template, the actual typed code only gets created when you call the function. How can the compiler make an object out of something if it doesn't know the type?

I have seen strategies such as this:
1
2
3
4
5
6
7
8
9
// file.h
#ifndef FILE_H
#define FILE_H

template <typename T>
void func( const T& value );

#include <file.cpp>
#endif 

1
2
3
4
5
6
// file.cpp
template < typename T>
void func( const T& value )
{
  // do it
}


Which will technically work. However, you must be sure not to try to compile file.cpp into an object. As you get better at writing makefiles, you will see that having certain cpp files that should not be compiled only complicates things.

I like your strategy of not having .cpp file if it should not be compiled.
So I guess Row.h does not need a compile command because it is included by other files as needed. For those files I added Row.h to Makefile dependencies.

Thank you for sharing your insights; I learned something today.
Topic archived. No new replies allowed.