A linking error is occurring after templating one of my functions. I had previously declared quicksort as:
std::vector<double> quicksort ( std::vector<double> unsorted_list );
After templating, I now get a linker error.
Scanning dependencies of target Quicksort
[ 25%] Building CXX object Quicksort/CMakeFiles/http://ift.tt/2s5Q9yJ
[ 50%] Linking CXX static library libQuicksort.a
[ 50%] Built target Quicksort
Scanning dependencies of target Sort
[ 75%] Building CXX object CMakeFiles/Sort.dir/sort.cxx.o
[100%] Linking CXX executable Sort
CMakeFiles/Sort.dir/sort.cxx.o: In function `main':
/home/pmp/C++/sort_algorithms/sort.cxx:(.text+0xdac): undefined reference to `std::vector<double, std::allocator<double> > quicksort<double, std::allocator<double> >(std::vector<double, std::allocator<double> >)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
CMakeFiles/http://ift.tt/2qMLmOQ: recipe for target 'Sort' failed
make[2]: *** [Sort] Error 1
CMakeFiles/Makefile2:387: recipe for target 'CMakeFiles/Sort.dir/all' failed
make[1]: *** [CMakeFiles/Sort.dir/all] Error 2
Makefile:138: recipe for target 'all' failed
make: *** [all] Error 2
I think isocpp suggests I append a declaration of my desired type below my definition.
template std::vector<double> quicksort( std::vector<double> );
This did work, but it seems like an unsatisfying solution. I thought the point of templates was to avoid having to declare each type you might need. Is this method the only way to resolve this kind of error?
Source below.
Caller
/* sort.cxx */
#include <iostream>
#include <vector>
#include <string>
#include "SortConfig.h"
#include "Quicksort.h"
int main ( int argc, char **argv )
{
if (argc < 2)
{
std::cout << "Usage : " << argv[0] << "nums ..." << std::endl;
return 1;
}
std::vector<std::string> arguments(argv + 1, argv + argc); // Init vector with args, need to refactor when adding more sort algos
std::vector<double> input_list;
input_list.reserve(arguments.size()); // Pre-reserve enough space in vector for copy
for (std::string arg : arguments)
{
input_list.push_back(std::stod(arg));
}
std::vector<double> sorted_list = quicksort(input_list); // Lets sort
std::string output_buffer;
for (double num : sorted_list)
{
output_buffer += std::to_string(num) + " ";
}
output_buffer.pop_back(); // Remove trailing space
std::cout << output_buffer << std::endl;
return 0;
}
Declaration
/* quicksort.h */
#ifndef __QUICKSORT_H__
#define __QUICKSORT_H__
#include <vector>
template<typename T, typename A>
std::vector<T,A> quicksort ( std::vector<T,A> unsorted_list );
#endif // __QUICKSORT_H__
Definition
/* quicksort.cxx */
#include <vector>
#include <iostream>
template<typename T, typename A>
std::vector<T,A> quicksort ( std::vector<T,A> unsorted_list )
{
if (unsorted_list.size() < 2)
{
return unsorted_list; // Trivial case
}
std::vector<T> lower_list;
std::vector<T> upper_list;
std::vector<T> sorted_list;
lower_list.reserve(unsorted_list.size());
upper_list.reserve(unsorted_list.size());
sorted_list.reserve(unsorted_list.size());
const T pivot = unsorted_list.front(); // Use first element as pivot
/* Divide unsorted list */
for( T val : unsorted_list )
{
if (val < pivot)
{
lower_list.push_back(val);
}
else if (val > pivot)
{
upper_list.push_back(val);
}
else // (val == pivot)
{
sorted_list.push_back(val);
}
}
/* Sort and merge sub lists */
if (lower_list.size() > 0)
{
lower_list = quicksort(lower_list);
sorted_list.insert(sorted_list.begin(), lower_list.begin(), lower_list.end());
}
if (upper_list.size() > 0)
{
upper_list = quicksort(upper_list);
sorted_list.insert(sorted_list.end(), upper_list.begin(), upper_list.end());
}
return sorted_list;
}
Aucun commentaire:
Enregistrer un commentaire