TL;DR
I was recieving an undefiend reference
error message when trying to run a program that had templated functions inside of a non-templated class. There were multiple solutions suggested in the comments of this thread, and the one I chose is illustrated at the end of this post.
Refer to the section headed as "Problem statement" bellow for the error output from my code.
Edit1: December 8, 2017:
- Changed my code samples to allow easy reproduction of the problem by just doing a simple copy/pasta to their own ide.
- A solution for this problem has been provided in the comments by both Kevin and DevSolar on this post -- big thanks guys! It turns out that I needed to do one of the following:
- Move the definition for my template functions from the .cpp file to the .h file.
- Explicitly provide definitions for the possible data types that could conceivably be passed through the template class type... This sounds like it would be a lot of work. I'm busy prepping for finals right now, but when I get a moment I'll come back and post the changed code to demo the fix.
Edit2: December 19, 2017:
- Seeing as the problem in the title of this post stemmed from improperly defining my templated functions in my non-tmplated class, I've decided to add a TL;DR at the front of the post for future reader convenience.
- Added my chosen solution strategy at the bottom of the posting.
- This should offer a clear demonstration of one means for using a templated function in a non-templated class.
Problem statement
using g++
to compile and link my class files is giving me the undefined reference
complaint where driver.cpp calls mergesortImproved::beginSorting(std::vector<int> &data)
. Apparently it can't find the definition for my function in mergesortImproved.cpp .
$ g++ -o msI_out -std=c++17 *.cpp
/tmp/ccZ0tzev.o: In function `generateTimeData(quicksort&, mergesort&, mergesortImproved&, int const&, long double&, std::vector<int, std::allocator<int> >&)':
driver.cpp:(.text+0xaac): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)'
collect2: error: ld returned 1 exit status
Side note, msI is how I've been abbreviating mergesortImproved. This is the required file name from the instructor, but seeing as it's a bit cumbersome I've taken to calling it msI.
I say this just in case msI pops up somewhere and I forget to correct the name back to mergesortImproved in this post.
The specific details of this situation
All files are in the same folder, and I've been sure to include all files in my attempts to compile and link.
I've also tried to compile on both a Windows 10 machine and on a Linux machine.
I've read many of the other similar questions, and it seems that 9 out of 10 times this problem comes from the programmer not compiling all of the files for the program like the should. So...
edit: almost forgot to include the g++ versions for the windows and linux machines I tried to use.
For the Windows 10 machine:
>gcc -v
"crazy alphabet-soup pops up, followed by:"
Thread model: posix
gcc version 7.2.0 (x86_64-posix-seh-rev1, Built by MinGW-W64 project)
For the Linux machine:
$gcc -v
"like windows, it starts with crazy alphabet-soup, followed by:"
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
Here are the different g++ calls I've tried:
Note on the console output lines shown below:
All error responses were originally very long single lines of output. I've taken the liberty breaking that output into multiple lines for the sake of easier readability.
ie., no having to search for where the undefined reference
is, along with other visual cues in terms of repeating format.
Linux attempts
Linux_attempt-1:
$ g++ -o msI_out -std=c++17 *.cpp In function `generateTimeData(quicksort&, mergesort&, mergesortImproved&, int const&, long double&, std::vector<int, std::allocator<int> >&)': driver.cpp:(.text+0xaac): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2: error: ld returned 1 exit status
(Same error as I showed in my problem statement above)
Linux_attempt-2:
$ g++ -o msI_out -std=c++17 driver.cpp quicksort.cpp mergesortImproved.cpp mergesort.cpp WorkDir.cpp /tmp/ccQzfFiq.o: In function `generateTimeData(quicksort&, mergesort&, mergesortImproved&, int const&, long double&, std::vector<int, std::allocator<int> >&)': driver.cpp:(.text+0xaac): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2: error: ld returned 1 exit status
(Same error as I showed in my problem statement above)
Linux_attempt-3:
$ g++ -c -std=c++17 driver.cpp quicksort.cpp mergesortImproved.cpp mergesort.cpp WorkDir.cpp $ g++ -o msI_out -std=c++17 driver.o quicksort.o mergesortImproved.o mergesort.o WorkDir.o driver.o: In function `generateTimeData(quicksort&, mergesort&, mergesortImproved&, int const&, long double&, std::vector<int, std::allocator<int> >&)': driver.cpp:(.text+0xaac): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2: error: ld returned 1 exit status
Windows 10 attempts
Windows_attempt-1:
>g++ -o msI_out -std=c++17 *.cpp \cc1alJ9m.o:driver.cpp:(.text+0x94f): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2.exe: error: ld returned 1 exit status
Windows_attempt-2:
>g++ -o msI_out -std=c++17 driver.cpp mergesort.cpp quicksort.cpp mergesortImproved.cpp WorkDir.cpp \ccGBGXAX.o:driver.cpp:(.text+0x94f): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2.exe: error: ld returned 1 exit status
Windows_attempt-3:
>g++ -c -std=c++17 driver.cpp quicksort.cpp mergesortImproved.cpp mergesort.cpp WorkDir.cpp >g++ -o msI_out -std=c++17 driver.o quicksort.o mergesortImproved.o mergesort.o WorkDir.o driver.o:driver.cpp:(.text+0x94f): undefined reference to `void mergesortImproved::beginSorting<int>(std::vector<int, std::allocator<int> >&)' collect2.exe: error: ld returned 1 exit status
A peek inside the files
- driver.cpp
- mergesortImproved.h
- mergesortImproved.cpp
driver.cpp
// driver.cpp
#include <iostream>
#include <vector>
#include "mergesortImproved.h"
using namespace std;
/** int main( int argc, char *argv[] )
*
* main(arc, argv) will perform the task of initializing sorting classes, output files, and control variables.
*
*
* @param argc The number of arguments passed on the command line.
* If argc == 1, then no additional arguments were passed, as the first argument is always the
* name of the executable file.
*
* @param argv An array of c_strings containing any command-line arguments beyond the initial executable's name.
* @return the error code should any be thrown, otherwise 0 when all goes well.
*/
int main( int argc, char *argv[] )
{
vector<int> sampleVector = {41, 8467, 6334, 6500, 9169, 5724, 1478, 9358, 6962, 4464, 5705, 8145, 3281, 6827};
mergesortImproved msI;
msI.beginSorting(sampleVector);
return 0;
}
mergesortImproved.h
#ifndef MSI_ASSIG4_MERGESORTIMPROVED_H
#define MSI_ASSIG4_MERGESORTIMPROVED_H
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
class mergesortImproved
{
public:
/** template<class Comparable> void beginSorting(vector<Comparable> &data)
*
* Handles preparations for iterative-in-place Mergesort. Namely, the math needed for locating and saving index pointers into
* queues and stacks that will later be used to emulate recursively subdeviding the unsorted collection before the much
* simpler task of recombining the imaginary subdivisions.
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template<class Comparable>
void beginSorting(vector<Comparable> &vector);
/** template <class Comparable> mergesortImproved(vector<Comparable> &data)
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template <class Comparable>
mergesortImproved(vector<Comparable> &data)
{
beginSorting(data);
}
mergesortImproved()=default;
private:
// omitted
};
#endif //MSI_ASSIG4_MERGESORTIMPROVED_H
mergesortImproved.cpp
#include "mergesortImproved.h"
using namespace std;
/** template<class Comparable> void beginSorting(vector<Comparable> &data)
*
* Handles preparations for iterative-in-place Mergesort. Namely, the math needed for locating and saving index pointers into
* queues and stacks that will later be used to emulate recursively subdeviding the unsorted collection before the much
* simpler task of recombining the imaginary subdivisions.
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template<class Comparable>
void mergesortImproved::beginSorting(vector<Comparable> &data)
{
// dummy functionality here, just demonstrating the conditions causing the linker error
cout << "Hey, it's running!!" << endl;
}
Example of the easiest solution
- driver.cpp
- mergesortImproved.h
- mergesortImproved.cpp
driver.cpp
(driver.cpp is completely unchanged from before, but I've shown it's code here for visual ease in seeing how things tie together.)
// driver.cpp
#include <iostream>
#include <vector>
#include "mergesortImproved.h"
using namespace std;
/** int main( int argc, char *argv[] )
*
* main(arc, argv) will perform the task of initializing sorting classes, output files, and control variables.
*
*
* @param argc The number of arguments passed on the command line.
* If argc == 1, then no additional arguments were passed, as the first argument is always the
* name of the executable file.
*
* @param argv An array of c_strings containing any command-line arguments beyond the initial executable's name.
* @return the error code should any be thrown, otherwise 0 when all goes well.
*/
int main( int argc, char *argv[] )
{
vector<int> sampleVector = {41, 8467, 6334, 6500, 9169, 5724, 1478, 9358, 6962, 4464, 5705, 8145, 3281, 6827};
mergesortImproved msI;
msI.beginSorting(sampleVector);
return 0;
}
mergesortImproved.h
#ifndef MSI_ASSIG4_MERGESORTIMPROVED_H
#define MSI_ASSIG4_MERGESORTIMPROVED_H
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
class mergesortImproved
{
public:
/** template<class Comparable> void beginSorting(vector<Comparable> &data)
*
* Handles preparations for iterative-in-place Mergesort. Namely, the math needed for locating and saving index pointers into
* queues and stacks that will later be used to emulate recursively subdeviding the unsorted collection before the much
* simpler task of recombining the imaginary subdivisions.
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template<class Comparable>
void mergesortImproved::beginSorting(std::vector<Comparable> &data)
{
// dummy functionality here, just demonstrating the conditions causing the linker error
cout << "Hey, it's running!!" << endl;
}
/** template<class Comparable> void beginSorting(vector<Comparable> &data)
*
* Handles preparations for iterative-in-place Mergesort. Namely, the math needed for locating and saving index pointers into
* queues and stacks that will later be used to emulate recursively subdeviding the unsorted collection before the much
* simpler task of recombining the imaginary subdivisions.
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template<class Comparable>
void beginSorting(vector<Comparable> &vector);
/** template <class Comparable> mergesortImproved(vector<Comparable> &data)
*
* @tparam Comparable This template reference is meant for use with data types that possess natural ordering.
* Although there are no assert restrictions in place to ensure you only use data types with natural
* ordering, the problem should become quickly apparant if the programmer fails to respect this
* requirement.
*
* @param data The vector<Comparable> that is to be sorted
*/
template <class Comparable>
mergesortImproved(vector<Comparable> &data)
{
beginSorting(data);
}
mergesortImproved()=default;
private:
// omitted
};
#endif //MSI_ASSIG4_MERGESORTIMPROVED_H
mergesortImproved.cpp
// because my original sample code had only the template function
// in it, this sample piece now appears empty.
// The reality is, I've moved all templated functions into the
// header file, which means this .cpp file only contains the
// non templated functions, which don't need to be shown for the
// purpose of this example.