编译器警告(等级 4)C4866

“file(line_number)”编译器可能不会在对 operator_name 的调用中强制执行从左到右计算顺序

注解

从 C++17 开始,运算符“->*”、“,”、“[]”和 << 的操作数必须按从左到右的顺序计算>>。 在以下两种情况下,编译器无法保证此顺序:

  • 其中一个操作数表达式是由值传递的对象或包含由值传递的对象时,或

  • 使用 /clr 进行编译,且其中的一个操作数是对象的字段或数组元素时。

当编译器无法保证从左到右计算时,它将发出警告 C4866。 只有在指定 /std:c++17 或更高版本时才会生成此警告,因为这些运算符的从左到右顺序要求是在 C++17 中引入的。

此警告默认处于关闭状态;可以使用 /Wall 或 /wN4866 在命令行上启用它(作为等级 N 警告),或者在源文件中使用 #pragma warning。 有关详细信息,请参阅默认关闭的编译器警告

由于 C++17 标准的编译器一致性工作,Visual Studio 2017 版本 15.9 中引入了此警告。 在 Visual Studio 2017 版本 15.9 之前的编译器版本中没有编译时警告的代码现在可能生成 C4866。 有关如何禁用特定编译器版本或更高版本中引入的警告的信息,请参阅由编译器版本引发的编译器警告

若要解决此警告,首先考虑运算符元素的从左到右计算是否是必需的,例如,元素的计算可能会生成依赖于顺序的副作用的情况。 在许多情况下,元素计算的顺序不会有什么明显的影响。

如果计算顺序必须是从左到右,则考虑是否可以改为通过 const 引用来传递元素。 此更改可消除以下代码示例中的警告。

示例

此示例将生成 C4866,并演示修复方法:

// C4866.cpp
// compile with: /w14866 /std:c++17

class HasCopyConstructor
{
public:
    int x;

    HasCopyConstructor(int x) : x(x) {}
    HasCopyConstructor(const HasCopyConstructor& h) : x(h.x) { }
};

int operator->*(HasCopyConstructor a, HasCopyConstructor b) { return a.x + b.x; }

// This version of operator->* does not trigger the warning:
// int operator->*(const HasCopyConstructor& a, const HasCopyConstructor& b) { return a.x + b.x; }

int main()
{
    HasCopyConstructor a{ 1 };
    HasCopyConstructor b{ 2 };

    a->*b;        // C4866 for call to operator->*
};