Compiler Warning (level 4) C4866
'file(line_number)' compiler may not enforce left-to-right evaluation order for call to operator_name
Remarks
Starting in C++17, the operands of the operators ->*, [], >>, and << must be evaluated in left-to-right order. There are two cases in which the compiler is unable to guarantee this order:
when one of the operand expressions is an object passed by value or contains an object passed by value, or
when compiled by using /clr, and one of the operands is a field of an object or an array element.
The compiler emits warning C4866 when it can't guarantee left-to-right evaluation. This warning is only generated if /std:c++17
or later is specified, as the left-to-right order requirement of these operators was introduced in C++17.
This warning is off by default; you can use /Wall or /wN4866 to enable it on the command line as a level N warning, or use #pragma warning in your source file. For more information, see Compiler warnings that are off by default.
This warning was introduced in Visual Studio 2017 version 15.9 as a result of compiler conformance work for the C++17 standard. Code that compiled without warnings in versions of the compiler before Visual Studio 2017 version 15.9 can now generate C4866. For information on how to disable warnings introduced in a particular compiler version or later, see Compiler Warnings by compiler version.
To resolve this warning, first consider whether left-to-right evaluation of the operator elements is necessary, such as when evaluation of the elements might produce order-dependent side-effects. In many cases, the order in which elements are evaluated does not have an observable effect.
If the order of evaluation must be left-to-right, consider whether you can pass the elements by const
reference instead. This change eliminates the warning in the following code sample.
Example
This sample generates C4866, and shows a way to fix it:
// 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->*
};