テンプレート中に出てくる `... || args` とは？

# TL; DR

https://cpprefjp.github.io/lang/cpp17/folding_expressions.html

> 畳み込み式 (fold expression) は可変引数テンプレートのパラメータパックに対して二項演算を累積的に行う

# はじめに

「[Learn LLVM 17](https://www.packtpub.com/en-sk/product/learn-llvm-17-9781837631346?type=print)」[^learn-llvm]を読んでいたところ、以下のコードに遭遇しました。

```cpp:tinylang/include/tinylang/Lexer/Token.h
// 言語処理系実装内、lexerのトークンの種類判別メソッド
template <typename... Tokens>
bool isOneOf(Tokens &&... Toks) const {
  return (... || is(Toks));
}
```

https://github.com/PacktPublishing/Learn-LLVM-17/blob/main/Chapter03/tinylang/include/tinylang/Lexer/Token.h#L35

3行目 `(... || is(Toks))` の部分が何をしているのが分からなかったので調べてみました。

(C++初心者なので誤った記述があればコメントいただけるとありがたいです）

# 畳み込み式

上記は **畳み込み式 (fold expression)** という構文で、C++17で導入されたものです。

https://cpprefjp.github.io/lang/cpp17/folding_expressions.html

可変長引数のテンプレートで2項演算子の一部に `...` を使用すると、各引数に対して順番にその演算子を適用します（`reduce` 関数のイメージです）。

```cpp
bool isOneOf(Tokens &&... Toks) const {
  return (... || is(Toks));
}

// 引数が1つの場合: isOneOf(a)
bool isOneOf(Token Tok1) {
  return (is(Tok1));
}

// 引数が2つの場合: isOneOf(a, b)
bool isOneOf(Token Tok1, Token Tok2) {
  return (is(Tok1) || is(Tok2));
}

// 引数が3つの場合: isOneOf(a, b, c)
bool isOneOf(Token Tok1, Token Tok2, Token Tok3) {
  return (is(Tok1) || is(Tok2) || is(Tok3));
}

// ...
```

もう少しシンプルな例で試してみます。

```cpp
#include <iostream>
using namespace std;

template<typename... Args> bool any(Args... args) {
  return (... || args);
}

int main(void){
  std::cout << any(false, false, true) << '\n'; // 1
  std::cout << any("foo", 0, 1) << '\n'; // 1
  std::cout << any(0, false, nullptr) << '\n'; // 0
}
```

展開されるテンプレートを確認すると、確かに各引数を順番に `||` した結果がreturnされています[^template]。

```bash
$ clang++ -Xclang -ast-print -fsyntax-only fold.cpp
```

```cpp
// ...
template<> bool any<<bool, bool, bool>>(bool args, bool args, bool args) {
    return args || args || args;
}
template<> bool any<<const char *, int, int>>(const char *args, int args, int args) {
    return args || args || args;
}
template<> bool any<<int, bool, std::nullptr_t>>(int args, bool args, std::nullptr_t args) {
    return args || args || args;
}
int main() {
    std::cout << any(false, false, true) << '\n';
    std::cout << any("foo", 0, 1) << '\n';
    std::cout << any(0, false, nullptr) << '\n';
}
```

テンプレートの展開は以下を参考にしました。

https://stackoverflow.com/questions/4448094/can-we-see-the-templates-instantiated-by-the-c-compiler

右側（最後の引数）から畳み込みを行いたい場合は `...` が右側に来るようにします。これで結合法則が成り立たない2項演算でも望み通りの順序で計算できます[^ast]。

```cpp
template<typename... Args> auto sub_left(Args... args) {
  return (... - args);
}

template<typename... Args> auto sub_right(Args... args) {
  return (args - ...);
}

int main(void){
  std::cout << sub_left(1, 2, 3) << '\n'; // ((1 - 2) - 3)
  std::cout << sub_right(1, 2, 3) << '\n'; // (1 - (2 - 3))
}
```

```
-4
2
```

# 余談: 構文の調べ方

記号の構文は検索しづらくなかなか知りたい情報にたどり着けなかったのですが（`c++ three dots operator` で調べても、可変長引数自体の解説しか出てこない）、Geminiに聞いたら一発で教えてくれました。

（追記）`...` は演算子ではないので、下記のGeminiの回答「`...` は、可変個のパラメータパックの展開を表す演算子です」は誤りでした。コメントありがとうございます。

![GIbX09iaIAAMcxq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/c019aace-6dbe-c778-fd13-7e9dfd032487.png)

<details><summary>(↑のプロンプト画像のテキスト)</summary>

> 私「以下のソースコード中、 `||` の直前にある `...` の意味を教えてください。また、この文法を表す名称があれば教えてください。」

```cpp
template <typename... Tokens>
 bool isOneOf(Tokens &&... Toks) const {
 return (... || is(Toks));
}
```

> Gemini「以下のソースコードにおける `...` は、可変個のパラメータパックの展開を表す演算子です。この文法は fold式 と呼ばれ、C++17で導入されました。」
</details>

生成AIはハルシネーションが怖くてあまり調べ物に使ってこなかったのですが、「この文法を表す名称があれば教えてください。」と聞いて、別途検索で事実確認をすれば安心して活用できそうです。

[^learn-llvm]: 手を動かし実際の言語処理系を作りながらLLVMについて学べる本です。本文のソースコードはlexerのトークン判別のメソッドです。~~C++をある程度学習してから読んだ方が良いと思います~~
[^template]: `nullptr` は、単にいろいろな型で試したかったので入れているだけです（深い意味はありません）。~~clangは警告を出してきます~~
[^ast]: 上記の `clang++ -Xclang -ast-print -fsyntax-only` でデバッグプリントした結果には変化がありませんでした。AST上は構造が変わっているはずなので、優先順位のカッコの表示を省略しているのでしょうか...？