英文:
Cannot pass struct to template function
问题
- 为什么 
comp在main函数中不起作用,但在其他排序函数中起作用? 
在您的 main 函数中,您创建了一个自定义比较结构体 Compare,但问题出在比较运算符的定义上。在 Compare 结构体中,您定义的 operator() 返回 first.size() < sec.size(),这意味着它将按字符串的长度升序排序。但是,您的排序函数期望的是一个降序排序(从长到短),因此 comp 在 main 函数中的使用与预期不符。
- 我该如何使这个代码按照我的意图工作?
 
如果您希望在 main 函数中使用 comp 对字符串按长度降序进行排序,您可以在 main 函数中使用 SortGreater 结构体,这样就能得到预期的结果。例如:
int main() {
    vector<string> str = {"aa", "a", "aaa"};
    vec::SortGreater<string> comp; // 使用 SortGreater 结构体
    vec::sort(str, comp);
    return 0;
}
这将使用 SortGreater 结构体,按字符串长度降序对 str 进行排序。
请确保您选择的比较结构体与排序方式一致,以获得预期的排序结果。
英文:
So I'm trying to create a sorting function that takes in an std::vector and struct and sorts the vector based on the struct. My code for the function is this:
template<typename T, typename C> void sort(vector<T> &array, C &comp) {
    vector<T> blank(array.size(), 0);
    mergeSort(array, blank, 0, array.size() - 1, comp);
}
The .cpp file is this:
#include "array.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Compare {
    bool operator()(const string &first, const string &sec) {
      return first.size() < sec.size();
    }  
};
int main() {
    vector<string> str = {"aa", "a", "aaa"};
    Compare comp;
    vec::sort(str, comp);
    
    return 0;
}
I tried this and many, many other variations of this code, but all of them end in error. This particular one says terminate called after throwing an instance of 'std::logic_error'.
what():  basic_string: construction from null is not valid
The full code for "array.h" is this:
#pragma once
#include <iostream>
#include <vector>
#include <cmath>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;
/*
* Provides many algorithms and functions used with std::vector's
* @author M. Farnsworth
*/
namespace vec {
    /*
    * Sorts an std::vector either ascending or descending depending on ltog (least to greatest).
    * If ltog is false it sorts the std::vector in descending.
    * Is a proxy function between the user and the actuall sorting function.
    * Implements the merge sort algorithm.
    */
    template<typename T> void sort(vector<T> &array, bool ltog = true);
    /*
    * Sorts an std::vector based on the 'comp' given to it.
    * Is a proxy function between the user and the actuall sorting function.
    * Implements the merge sort algorithm.
    * Overloads the first 'sort'.
    */
    template<typename T, typename C> void sort(vector<T> &array, C &comp);
    
    /*
    * Second function in merge sort.
    * Can be called by user directly, they will just need to provide values for the rest of the parameters.
    * Don't call this function, call arr::sort(vector<int> &array, bool ltog) to sort.
    */
    template<typename T, typename C> void mergeSort(vector<T> &array, vector<T> &blank, int bottom, int top, C &comp);
    
    /*
    * Third function in merge sort.
    * Shouldn't be called by the user.
    */
    template<typename T, typename C> void merge(vector<T> &array, vector<T> &copy, int bottom, int half, int top, C &comp);
    
    /*
    * Swaps items at the indices 'first' and 'second' of the given std::vector.
    */
    template<typename T> void swap(vector<T> &array, int first, int second);
    /*
    * Reverses the order of the items in an std::vector.
    */
    template<typename T> void reverse(vector<T> &array);
    /*
    * Writes the items in an std::vector to an std::ostream.
    * Essentially this means it will display the array.
    * If called with only the std::vector it will display to the console or 'cout' by default.
    */
    template<typename T> void display(vector<T> &array, string diliminator = " ", bool endline = true, ostream &out = cout);
    /*
    * Provides a structor for comparing two T.
    * operator() returns true if first is less than second.
    * operator() returns false if first is greater or equal to second.
    * Used in 'merge' to sort an std::vector in ascending order.
    */
    template<typename T> struct SortLess;
    /*
    * Provides a structor for comparing two T.
    * operator() returns false if first is less than second.
    * operator() returns true if first is greater or equal to second.
    * Used in 'merge' to sort an std::vector in descending order.
    */
    template<typename T> struct SortGreater;
    template<typename T> struct SortLess {
        bool operator()(T &first, T &second) {
            return first < second;
        }
    };
    template<typename T> struct SortGreater {
        bool operator()(T &first, T &second) {
            return first > second;
        }
    };
    template<typename T> void sort(vector<T> &array, bool ltog) {
        vector<T> blank(array.size(), 0);
        if (ltog) {
            SortLess<T> comp;
            mergeSort(array, blank, 0, array.size() - 1, comp);
        } else {
            SortGreater<T> comp;
            mergeSort(array, blank, 0, array.size() - 1, comp);
        }
    }
    template<typename T, typename C> void sort(vector<T> &array, C &comp) {
        vector<T> blank(array.size(), 0);
        mergeSort(array, blank, 0, array.size() - 1, comp);
    }
    template<typename T, typename C> void mergeSort(vector<T> &array, vector<T> &blank, int bottom, int top, C &comp) {
        if (top != bottom) {
            int half = bottom + (top - bottom) / 2;
            mergeSort(array, blank, bottom, half, comp);
            mergeSort(array, blank, half + 1, top, comp);
            merge(array, blank, bottom, half, top, comp);
        }
    }
    template<typename T, typename C> void merge(vector<T> &array, vector<T> &copy, int bottom, int half, int top, C &comp) {
        for (int i = 0; i < array.size(); i++) {
            copy[i] = array[i];
        }
        
        int firstCount = bottom;
        int secCount = half + 1;
        int count = firstCount;
        
        while (firstCount <= half && secCount <= top) {
            if (comp(copy[firstCount], copy[secCount])) {
                array[count] = copy[firstCount];
                firstCount++;
            } else {
                array[count] = copy[secCount];
                secCount++;
            }
            count++;
        }
        
        for (int i = firstCount; i <= half; i++) {
            array[count] = copy[i];
            count++;
        }
        
        for (int i = secCount; i <= top; i++) {
            array[count] = copy[i];
            count++;
        }
    }
    template<typename T> void swap(vector<T> &array, int first, int second) {
        int temp = array[first];
        array[first] = array[second];
        array[second] = temp;
    }
    template<typename T> void reverse(vector<T> &array) {
        int len = array.size();
        for (int i = 0; i < ceil(len / 2.0); i++) {
            swap(array, i, len - 1 - i);
        }
    }
    template<typename T> void display(vector<T> &array, string diliminator, bool endline, ostream &out) {
        for (int i = 0; i < array.size(); i++) {
            out << array[i] << diliminator;
        }
        if (endline) out << endl;
    }
    
    template<typename T> void shuffle(vector<T> &array) {
        srand(time(0));
        for (int i = 0; i < array.size(); i++) {
            int k = rand() % (i + 1);
            swap(array, i, k);
        }
    }
};
So my question is two-fold:
- Why does the comp not work in main, but does int the other sort function?
 - What can I do to make this work as I intend?
 
答案1
得分: 2
vector<T> blank(array.size(), 0);
这里你尝试创建一个大小为array.size()的vector<T>,但你想要用来复制到新的vector中的std::string是0,这被解释为const char*,并尝试从内存中的那个位置读取数据,这会导致_未定义的行为_,因为它尝试使用以下std::string构造函数:
constexpr std::string(const char* s, const Allocator& alloc = Allocator());
为了用空的string填充它,只需省略第二个参数:
vector<T> blank(array.size());
英文:
vector<T> blank(array.size(), 0);
Here you try to create a vector<string> with the size array.size() - but the std::string that you want to use for copying into the new vector is 0, which is interpreted as a const char* - and it tries to read from that place in memory with undefined behavior as a result using the std::string constructor:
constexpr std::string(const char* s, const Allocator& alloc = Allocator() );
In order to populate it with empty strings, simple leave the second argument out:
vector<T> blank(array.size());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论