コンパイラ警告 (レベル 4) C4866

'file(line_number)' コンパイラは operator_name の呼び出しに対して左から右への評価順序を強制しない可能性があります

解説

C++ 17 以降、演算子 ->*[], >><< のオペランドは左から右の順に評価する必要があります。 コンパイラでこの順序を保証できないケースが 2 つあります。

  • オペランド式の 1 つが値渡しされるオブジェクトであるか、値渡しされるオブジェクトを含んでいる場合、または

  • /clr を使ってコンパイルされ、かつオペランドの 1 つがオブジェクトのフィールドか配列要素である場合。

コンパイラで左から右の評価を保証できない場合、警告 C4866 が生成されます。 これらの演算子に対する左から右の順序の要件は C++ 17 で導入されたため、この警告が生成されるのは /std:c++17 以降を指定した場合のみです。

この警告は既定でオフになっています。/Wall または /wN4866 を使ってコマンドラインでレベル N 警告として有効にするか、ソースファイルで #pragma 警告を使って有効にしてください。 詳細については、「既定で無効になっているコンパイラ警告」を参照してください。

この警告は、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->*
};