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

时间:2016-06-30 17:00:48

标签: c++ recursion

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

我的功能有以下签名:

template<class RandomIt, class Compare>
void Merge(RandomIt begin, RandomIt middle, RandomIt end, Compare Comp);

我有一个聪明的想法,在开始时检查[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)
    //...
}

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

fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)

我创建了一个little stand-alone application on ideone.com来重现错误。

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

2 个答案:

答案 0 :(得分:2)

这里的问题是,您在递归的每个步骤创建函数Merge的新实例化,即首次从reverse_iterator创建randomaccess_iterator。然后编译器从reverse_iterator创建reverse_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;
}

答案 1 :(得分:0)

问题是Merge<it>需要Merge<std::reverse_iterator<it>>,这需要Merge<std::reverse_iterator<std::reverse_iterator<it>>,这需要Merge<std::reverse_iterator<std::reverse_iterator<std::reverse_iterator<it>>>,这需要Merge<std::reverse_iterator<std::reverse_iterator<std::reverse_iterator<std::re‌​verse_iterator<it>>>>,这需要......

所以你想要的是已经反转的迭代器的ReverseIterator(使用原始迭代器。所以你需要帮助函数:

template <class RandomIt>
RandomIt ReverseIt(std::reverse_iterator<RandomIt> it) {
    return it.base();
}
template <class RandomIt>
std::reverse_iterator<RandomIt> ReverseIt(RandomIt it) {
    return std::reverse_iterator<RandomIt>(it);
}

template<class RandomIt, class Compare=std::less<typename std::iterator_traits<RandomIt>::value_type>>
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) {
        Merge(ReverseIt(end), ReverseIt(std::next(middle)), ReverseIt(begin), Comp);
        return;
    }
    //Now [begin,middle) is guaranteed <= [middle,end)
    //...
}

汇编证明:http://coliru.stacked-crooked.com/a/741d73f889594e36