调用参数排列不变函数 f(i++, i++)
Calling an argument-permutation-invariant function f(i++, i++)
>假设我有一个函数foo(x, y, z)
它是不变的w.r.t.其参数的所有排列。我还有一个迭代器it
,这样迭代器it
、it + 1
和it + 2
就可以取消引用。
写好吗
... = foo(*it++, *it++, *it++); // (1)
而不是
... = foo(*it, *(it + 1), *(it + 2)); // (2)
?
据我了解,从技术上讲,自 C++17 年以来是正确的,因为(引用 cppreference.com 并考虑到it
可以是原始指针(
15(在函数调用中,值计算和每个参数初始化的副作用相对于任何其他参数的值计算和副作用是不确定的。
函数参数的求值顺序没有定义,但对于foo()
来说,顺序无关紧要。
但这是一种可接受的编码风格吗?一方面,(1)
很好地对称,暗示foo
具有这样的不变性,(2)
看起来有些丑陋。另一方面,(1)
立即对其正确性提出了质疑 - 阅读代码的人应该检查foo
的描述或定义以验证调用的正确性。
如果foo()
体很小,并且从函数定义中可以明显看出不变性,您会接受(1)
吗?
(可能,这个问题是基于意见的。但我忍不住问了。
你是对的,在 C++17
foo(*it++, *it++, *it++);
不是未定义的行为。 正如您的报价所述,如 [expr.call]/8 中所述
后缀表达式在表达式列表中的每个表达式和任何默认参数之前排序。参数的初始化,包括每个关联的值计算和副作用,相对于任何其他参数的初始化都是不确定的。
每个增量都是按顺序排列的,因此您不会有多个未排序的写入。 函数参数的计算顺序在 C++17 中仍未指定,因此这意味着您只有未指定的行为(您无法知道将哪个元素传递给每个参数(。
只要你的函数不关心这个,那么你就没问题。 如果参数的顺序很重要,那么您将不得不使用第二个版本。
这一切都说我更喜欢使用
foo(*it, *(it + 1), *(it + 2));
即使顺序无关紧要。 它使代码向后兼容,恕我直言,它更容易推理。 我宁愿在 for 循环的增量部分看到一个it += 3
,然后在函数调用中看到多个增量,而在循环的增量部分没有增量。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗