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->*
};