c++ - 调用运算符参数评估顺序
问题描述
#include <string>
struct X
{
char y;
std::string z;
X & operator()(std::string && s)
{
z = std::move(s);
return *this;
}
X & operator()(char c)
{
y = c;
return *this;
}
};
int main()
{
X x;
std::string y("abc");
x(y[0])(std::move(y));
}
是main
未定义行为的最后一行吗?我猜是的,因为它会展开如下,但只是想确保对调用运算符或成员函数调用没有更严格的保证
X::operator()(&X::operator()(&x, y[0]), std::move(z))
请添加来自标准或 cppref 的引用
解决方案
在 c++17 之前,链接修改相同左值的函数调用,就像在你的例子中一样,确实是未定义的行为,因为这些表达式的评估顺序是未指定的。
但是,修复该问题的提案已合并到 c++17 中。
这是相关规则(重点是我的),其中还包含提案中的一个示例,该示例显示了它是如何工作的:
后缀表达式在表达式列表中的每个表达式和任何默认参数之前排序。参数的初始化,包括每个相关的值计算和副作用,相对于任何其他参数的初始化顺序是不确定的。[注意:参数评估的所有副作用在输入函数之前进行排序(参见 [intro.execution])。— 尾注] [示例:
void f() { std::string s = "but I have heard it works even if you don't believe in it"; s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, ""); assert(s == "I have heard it works only if you believe in it"); // OK }
——结束示例]
虽然上述规则仅严格引用内置的operator()
,并且您有用户定义的运算符,但由于此规则,有关评估顺序的相同规则适用:
如果任一操作数的类型是类或枚举,则可能会声明实现此运算符的用户定义的运算符函数,或者可能需要用户定义的转换将操作数转换为适合于内置的类型。在运算符中。...但是,操作数按照内置 operator 规定的顺序进行排序。
推荐阅读
- java - java多态和接口实现
- python-3.x - 寻找函数的最优解
- java - 我的 Eclipse 目录中 /configuration/ 中的包是用来做什么的?
- android - DialogFlow - 防止同时触发多个顶级意图
- python - 签名与类中的基方法不匹配
- python - Python/Pandas:如何从每个 ID 的第二行获取特定列并将其放置在 ID 第一行的新列中?
- c++ - C++20 范围太多 | 运营商?
- java - 越界错误匹配矩阵中的单元格
- laravel - Laravel - 3 个具有多种关系的模型
- swift - UITableView titleForHeaderInSection 很大,字体不同