Reputation: 1279
I am new to C++ and am having difficulties resolving an Undefined Reference problem that I am running into. I am trying to create a test class that takes as input an array into a constructor, and everything seems to work if I have everything located in one file as below:
main.cpp
#include <iostream>
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
When I run this example, I get the following output:
Array constructor was called
Size of array is: 10
However, when I break this example up into the following three files:
Test.h
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
Test.cpp
#include "Test.h"
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
main.cpp
#include "Test.h"
#include <iostream>
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
I receive an undefined reference to Test::Test<int, 10>(int (&) [10])'
. I am not exactly sure what I am doing incorrectly and am thinking that perhaps I am overlooking something. Any insight would be appreciated. Thank you for the help.
Upvotes: 0
Views: 319
Reputation: 361
The problem is you are seperating out your template function declaration and template function definition. When you define a template function, your declaration of the function and its definition must be co-located. If not co-located, you should define your template function in a .tpp file and then include that .tpp file in the header file where your template function is declared.
Why is this required? Unlike your normal functions, where the type of the parameters is known beforehand, the compiler loads one version of the template function for every invocation of the function with a different type. So, in your case, when you do,
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
What the compiler does is, define a function definition,
Test::Test(int (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
and load this into memory. However, if the compiler has to do this, it has to have access to the definition of the function when it tries to look over the declaration in the header file. When you put the defintion of the function in a seperate .cpp file, the compiler does not have access to the definition of the function and hence cannot define and load the function into memory based on the user input.
Like I mentioned, if you want to seperate out the implementation from the definition, you can put the definition of the template function in a .tpp(which is a specialized file for template function definitions) file and include that in your .h. Something like this.
Test.h :
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
#include "Test.tpp"
Test.tpp
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
main.cpp
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
Hope this helps.
Upvotes: 1
Reputation: 192
Try this:
#include <iostream>
template<typename T>
class Test
{
public:
Test(T *array, int SIZE)
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
};
#include <iostream>
template<typename T>
class Test
{
public:
Test(T *array, int SIZE)
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
};
You probably want to use a std::vector
instead of arrays. This way you do not always have to reference the size of the array before you use it. It is much easier to manage.
Additionally, template classes are better off implemented in their header file.
Upvotes: 0