为啥将迭代器作为参数传递并在尾部位置递归时后缀失败并且前缀工作正常? [复制]

     2023-02-22     274

关键词:

【中文标题】为啥将迭代器作为参数传递并在尾部位置递归时后缀失败并且前缀工作正常? [复制]【英文标题】:Why does postfix failed and prefix work fine when pass an iterator as argument and recurse it at tail position? [duplicate]为什么将迭代器作为参数传递并在尾部位置递归时后缀失败并且前缀工作正常? [复制] 【发布时间】:2017-10-10 16:31:40 【问题描述】:

我偶然遇到了这个问题。

本以为google肯定能解决,但是搜索了多个关键词后,还是找不到答案,让我很困惑。

当我在尾部位置使用前缀时,代码可以正常工作:

template<class ContinerIterator, class F>
constexpr auto fun(ContinerIterator IteratorBegin, ContinerIterator IteratorEnd, F f)

    switch (IteratorBegin == IteratorEnd)
    
    case true: return;
    case false: f(*IteratorBegin);
    
    return fun(++IteratorBegin, IteratorEnd, f);

int main()

    std::vector<int> a =  1, 2, 3, 4 ;
    fun(std::begin(a), std::end(a), [](auto &a)->autoa *= 2; );
    for (auto v : a)
    
        std::cout << v << std::endl;
    
    return 0;

1

2

3

4

按任意键继续。 . .


Howerer,如果我使用后缀,IteratorBegin 神经到达 iteratorEnd 并走得很远,所以段错误。

template<class ContinerIterator, class F>
constexpr auto fun(ContinerIterator IteratorBegin, ContinerIterator IteratorEnd, F f)

    switch (IteratorBegin == IteratorEnd)
    
    case true: return;
    case false: f(*IteratorBegin);
    
    return fun(IteratorBegin++, IteratorEnd, f);

void test()



int main()

    std::vector<int> a =  1, 2, 3, 4 ;
    fun(std::begin(a), std::end(a), [](auto &a)->autoa *= 2; );
    for (auto v : a)
    
        std::cout << v << std::endl;
    
    return 0;

我尝试过 MSVC、G++、Clang,都失败了。 这是 gcc 的错误列表:

分段错误(核心转储)

这是 Clang 的:

发生错误(超时)。请稍后再试。

【问题讨论】:

听起来您可能需要学习如何使用调试器来单步调试您的代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。延伸阅读:How to debug small programs 如果postfix按照通常的语义来实现,应该很明显了。 以这种方式使用 switch 语句是不寻常的。我只是使用一个普通的旧 if/else。 @NathanOliver 我试过调试,比如step into function,然后发现IteratorBeginner不断增加。 @NathanOliver 谢谢!我很粗心,没有注意到迭代器本身仍然是同一个地址,不同的是它的值。可能是熬夜很多天的结果吧,lol。 【参考方案1】:

此声明

return fun(IteratorBegin++, IteratorEnd, f);

除了一些例外可以考虑像

fun(IteratorBegin, IteratorEnd, f);
++IteratorBegin;
return;

所以函数总是使用相同的IteratorBegin 值调用。

来自 C++ 标准(5.2.6 递增和递减)

1 后缀 ++ 表达式的值是其操作数的值。 [ 注意:得到的值是原值的副本——尾注 ]...

考虑以下简单程序

#include <iostream>

void f(int x)

    std::cout << "Inside f( x ): x = " << x << std::endl;


int main()

    int x = 0;

    std::cout << "Before f( x ): x = " << x << std::endl;
    f(x++);
    std::cout << "After  f( x ): x = " << x << std::endl;

    return 0;

它的输出是

Before f( x ): x = 0
Inside f( x ): x = 0
After  f( x ): x = 1

考虑以下简单程序也会很有用

#include <iostream>

int x = 0;

void f(int x)

    std::cout << "Local (parameter) x = " << x << std::endl;
    std::cout << "Global variable ::x = " << ::x << std::endl;


int main()

    f(x++);

    return 0;

它的输出是

Local (parameter) x = 0
Global variable ::x = 1

【讨论】:

【参考方案2】:

前缀大小写:

return fun(++IteratorBegin, IteratorEnd, f);

说,首先IteratorBegin加一,然后调用函数fun。之后,返回。

另一方面,后缀大小写:

return fun(IteratorBegin++, IteratorEnd, f);

说,先调用fun(),然后递增迭代器,然后返回。

这意味着fun() 总是被非递增迭代器调用。

【讨论】:

【参考方案3】:

在尾调用中使用后缀增量时,递归调用不会获取迭代器的增量值。它在应用增量之前获取迭代器的值。因此,递归是无限的。这会导致堆栈溢出。

【讨论】:

为啥我需要另一个迭代器作为 std::copy() 中的参数?

】为啥我需要另一个迭代器作为std::copy()中的参数?【英文标题】:WhydoIneedanotheriteratorasanargumentinstd::copy()?为什么我需要另一个迭代器作为std::copy()中的参数?【发布时间】:2019-09-1008:02:43【问题描述】:我不明白为什么我需要... 查看详情

为啥数组不能作为函数参数传递?

】为啥数组不能作为函数参数传递?【英文标题】:Whycan\'tarraysbepassedasfunctionarguments?为什么数组不能作为函数参数传递?【发布时间】:2011-10-2717:48:17【问题描述】:为什么不能将数组作为函数参数传递?我一直在阅读这本C++... 查看详情

C++:为啥我不能将一对迭代器传递给 regex_search?

】C++:为啥我不能将一对迭代器传递给regex_search?【英文标题】:C++:WhyIcan\'tpassapairofiteratorstoregex_search?C++:为什么我不能将一对迭代器传递给regex_search?【发布时间】:2015-10-2316:40:17【问题描述】:我尝试传递一对迭代器来表... 查看详情

当函数作为参数传递时,为啥按钮颜色会变为禁用按钮颜色?

】当函数作为参数传递时,为啥按钮颜色会变为禁用按钮颜色?【英文标题】:Whybuttoncolorchangestodisabledbuttoncolorwhenafunctionispassedasaparameter?当函数作为参数传递时,为什么按钮颜色会变为禁用按钮颜色?【发布时间】:2021-09-2804:5... 查看详情

Leetcode 494 蛮力递归解决方案将变量作为属性使用,但当我将其作为参数传递时不起作用

】Leetcode494蛮力递归解决方案将变量作为属性使用,但当我将其作为参数传递时不起作用【英文标题】:Leetcode494Bruteforcerecursivesolutionworkswithavariableasaattributebutdoesn\'tworkwhenIpassitasparameter【发布时间】:2021-12-2614:11:26【问题描述】... 查看详情

将成员函数作为参数传递/c++

...题描述】:我想在C++中实现一个类b,它可以通过封装该迭代器类型的成员集进行某种迭代。喜欢:b_object.for_each_x_do(function_f);所以function_f会得到x成员中的每个人并做任何事情。比方说:voidfunction_f(x_ 查看详情

为啥将函数作为函数的参数传递?

】为啥将函数作为函数的参数传递?【英文标题】:whypassasargumentofafunctionafunction?为什么将函数作为函数的参数传递?【发布时间】:2019-07-1017:27:25【问题描述】:我有一个小问题。我正在用devc++学习C(作为开始),我已经看到... 查看详情

为啥 QVector 的迭代器使用前缀增加而后缀在内部减少?

】为啥QVector的迭代器使用前缀增加而后缀在内部减少?【英文标题】:WhyisQVector\'siteratorusingprefixedincreasebutpostfixdecreaseinternally?为什么QVector的迭代器使用前缀增加而后缀在内部减少?【发布时间】:2016-01-1114:26:00【问题描述】:... 查看详情

从装饰器传递位置参数时如何支持静态和类方法?

】从装饰器传递位置参数时如何支持静态和类方法?【英文标题】:Howtosupportstaticandclassmethodswhenpassingpositionalargumentsfromadecorator?【发布时间】:2016-07-0316:46:55【问题描述】:我想编写一个装饰器,它在第一个位置(但在self或cls... 查看详情

为啥不能将运算符作为参数传递? [关闭]

】为啥不能将运算符作为参数传递?[关闭]【英文标题】:Whyisitnotpossibletopassanoperatorasanargument?[closed]为什么不能将运算符作为参数传递?[关闭]【发布时间】:2013-06-0620:45:57【问题描述】:我正在尝试编写一个具有LINQ查询的方法... 查看详情

Delphi x64:如何将本地过程作为过程参数(回调)传递

...年前,我将一个旧的unix应用程序移植到Delphi5。对于链表迭代,它使用通过地址传递给全局“迭代器”函数的本地过程。下面是一个简化的例子:typeTPerformPr 查看详情

为啥我不能将常量数组作为参数传递?

】为啥我不能将常量数组作为参数传递?【英文标题】:Whycan\'tIpassconstantarraysasarguments?为什么我不能将常量数组作为参数传递?【发布时间】:2016-08-1607:17:42【问题描述】:在C中,为什么我不能这样做:arrayfn(1.0,2.0,3.0);如果arra... 查看详情

为啥我们不能将字符串作为模板参数传递?

】为啥我们不能将字符串作为模板参数传递?【英文标题】:Whycan\'twepassstringsastemplatearguments?为什么我们不能将字符串作为模板参数传递?【发布时间】:2013-09-2000:32:42【问题描述】:我知道我们可以使用常量定义模板。例如:... 查看详情

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?

】当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?【英文标题】:Whyisthecopyconstructorcalledwhenwepassanobjectasanargumentbyvaluetoamethod?当我们将对象作为参数传递给方法时,为什么会调用复制构造函数?【发布时间】:20... 查看详情

为啥我们在传递二维数组作为参数时需要指定列大小?

】为啥我们在传递二维数组作为参数时需要指定列大小?【英文标题】:Whydoweneedtospecifythecolumnsizewhenpassinga2Darrayasaparameter?为什么我们在传递二维数组作为参数时需要指定列大小?【发布时间】:2012-09-3013:53:47【问题描述】:为... 查看详情

为啥在将命令行图像文件中的参数作为参数传递时出现错误

】为啥在将命令行图像文件中的参数作为参数传递时出现错误【英文标题】:Whyamgettingerrorswhilepassingargumetsfromcommadlineimagefileasanargument为什么在将命令行图像文件中的参数作为参数传递时出现错误【发布时间】:2021-09-3006:23:17【... 查看详情

为啥列表迭代器在 SGI STLs 实现中具有三个模板参数?

】为啥列表迭代器在SGISTLs实现中具有三个模板参数?【英文标题】:WhylistiteratorhasthreetemplateargumentsinSGISTL\'simplemention?为什么列表迭代器在SGISTLs实现中具有三个模板参数?【发布时间】:2018-06-2911:29:16【问题描述】:我在阅读SGI... 查看详情

装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效

】装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效【英文标题】:Decoratoronlyworkswhenmethodisdecoratedbutnotwhenthedecoratoriscalledwithmethodpassedasargument【发布时间】:2022-01-1920:12:40【问题描述】:长期聆听者;... 查看详情