samedi 3 juin 2017

Vector template link error

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