更改类型后,递归到模板化函数

Vic*_*one 6 c++ recursion

我目前正在为练习编写自己的合并排序实现.合并列表的左侧和右侧部分时,创建仅包含两侧较小的临时列表是有意义的.但是,逻辑会根据复制到temp的一侧而改变.

我的功能有以下签名:

template<class RandomIt, class Compare>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp);
Run Code Online (Sandbox Code Playgroud)

我有一个聪明的想法来检查[begin,middle)[middle,end)开头的长度,如果左边更大,将迭代器转换为反向迭代器并递归调用该函数.像这样:

template<class RandomIt, class Compare>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp) {
    size_t leftLength = std::distance(begin, middle);
    size_t rightLength = std::distance(middle, end);

    if (leftLength > rightLength) {
        using ReverseIterator = std::reverse_iterator<RandomIt>;
        Merge(ReverseIterator(end), ReverseIterator(std::next(middle)), ReverseIterator(begin), Comp);
        return;
    }
    //Now [begin,middle) is guaranteed <= [middle,end)
    //...
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器会出现相当粗的错误.

fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
Run Code Online (Sandbox Code Playgroud)

在ideone.com上创建了一个可以重现错误的独立应用程序.

编辑:对于mergesort,我只是意识到这不会起作用,因为需要反转Compare函数.

Aru*_*nmu 2

这里的问题是,您Merge在递归的每一步都创建了函数的新实例,即第一次reverse_iteratorrandomaccess_iterator. 然后编译器创建一个reverse_iteratorfromreverse_iterator等等......

正如您在创建迭代器时必须注意到的那样,reverse_iterator迭代器的模板类型不断变化......从而创建模板化函数的新实例。

简而言之,您对迭代器的使用是错误的。

这可能有效:

template <class RandomIt, class RevIt>
void Test(RandomIt begin, RandomIt middle, RandomIt end, RevIt rit) {
        size_t leftLength = std::distance(begin, middle);
        size_t rightLength = std::distance(middle, end);
        if (leftLength > rightLength) {
                Test(RevIt(end), RevIt(middle), RevIt(begin), rit);
                return;
        }
}

template <typename RandomIt>
void Test(RandomIt begin, RandomIt middle, RandomIt end) {
  Test(begin, middle, end, std::reverse_iterator<RandomIt>());
}

int main() {
        std::vector<int> nums = { 2, 1, 123, 1, 23, 123, 123, 5234, 52, 3, 452, 3, 452, 5 };
        int middle;
        std::cin >> middle;
        Test(nums.begin(), nums.begin()+middle, nums.end());
        return 0;
}
Run Code Online (Sandbox Code Playgroud)