C++で引数に関数を与えた時の評価順の動作を複数のコンパイラで試してみる

# 概要

このエントリでは、C++で引数に関数を与えた時の評価順の動作を複数のコンパイラで試してみます。

## 対象読者

- (筆者と同じくらい)C++の初心者の方

# 試したいこと

C++(少なくともC++17まで)では、引数として関数を与えた時の評価順は、仕様としては特に決めてありません(エントリ末尾に参考リンク)。例えば、下記のようなコードで、funcAll(funcA(), funcB())を呼んだときの評価順は、コンパイラ製作者側が決めていることになります。

```c++
int funcA() {
..
}

int funcB() {
..
}

void funcAll(int a, int b) {
}

//この時の、funcAll(funcA(), funcB());

```

# 準備

## コード

下記のようなコードを作り、標準出力に

```c++
#include<iostream>
using namespace std;

int funcA() {
    cout << "funcA" << endl;
    return 1;
}

int funcB() {
    cout << "funcB" << endl;
    return 2;
}

void funcAll(int a, int b) {
    cout << "funcAll" << endl;
}

int main() {
    funcAll(funcA(), funcB());
    cout << flush;
    return 0;
}

```

## 環境

- Windows10 Pro(x64) / Visual Studio Community 2019
- CentOS7(x64) / Clang, G++, Sun Studio(x86)

(IntelのコンパイラとEmbarcadero(Borland)のコンパイラも試してみたいものだという気持ちが一瞬よぎりましたが、利用条件とか時間の都合上、パスしました)

### Visual StudioのVisual C++

Intel用のNative

```console
> cl
Microsoft(R) C/C++ Optimizing Compiler Version 19.25.28614 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.
```

.NET用

```
>cl /clr
Microsoft(R) C/C++ Optimizing Compiler Version 19.25.28614
Microsoft (R) .NET Framework の場合 バージョン 4.08.4150.0
Copyright (C) Microsoft Corporation.  All rights reserved.
```

### ClangのC++コンパイラ

```console
$ clang++ --version
clang version 3.4.2 (tags/RELEASE_34/dot2-final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
```

### G++

```console
$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

### Sun CC

```console
$ sunCC -V
CC: Studio 12.6 Sun C++ 5.15 Linux_i386 2017/05/30
```

# 試してみる

## Visual C++(Native)

コンパイル

```console
cl main.cpp
```

動作結果

```console
funcB
funcA
funcAll
```

（参考）ファイルタイプをmingwのfileコマンドで確認

```
$ file main.exe
main.exe: PE32+ executable (console) x86-64, for MS Windows
```

## Visual C++(.NET CLI)

コンパイル

```console
cl /clr main.cpp
```

動作結果

```console
funcA
funcB
funcAll
```

（参考）ファイルタイプをmingwのfileコマンドで確認

```
$ file main.exe
main.exe: PE32+ executable (console) x86-64 Mono/.Net assembly, for MS Windows
```


## Clang

コンパイル

```console
$ clang++ main.cpp
```

動作結果

```console
funcA
funcB
funcAll
```

## G++

コンパイル

```console
g++ main.cpp
```

動作結果

```console
funcB
funcA
funcAll
```

## Sun CC

コンパイル

```console
CC main.cpp
```

動作結果

```console
funcA
funcB
funcAll
```

## 試してみたものまとめ

上記をまとめると下表のようになります。コンパイラ（オプション）によって、動作が異なることを確認しました。（へー。知らんかった。）

|評価順|コンパイラ(オプション)|
|:--:|:--|
|funcA->funcB|Visual C++(.NET CLI), Clang C++, Sun CC|
|funcB->funcA|Visual C++(Native), G++|



# 参考

## C++の仕様

C++の仕様書は、[ISO/IECからお買い上げ](https://www.iso.org/standard/68564.html)するのが正確ですが、その一歩手前の[ドラフト版がGitHubで公開されているので参照](https://github.com/cplusplus/draft)することができます。

[PDFになっている版](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf)で、「5.2.2  Function call」のあたりとか、そこから飛んで「§ 1.9」のあたりに関連する説明があります。

## 情報サイト

- [cppreferenceの中の記載](https://en.cppreference.com/w/cpp/language/eval_order) が見やすかったです。

## 個人サイト

- [yohhoyの日記 C/C++関数引数の評価順序](https://yohhoy.hatenadiary.jp/entry/20120304/p1)