「C++の基礎 - 可変長引数」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
(Wiki がページ「可変長引数を実現する方法(C++)」を「C++の基礎 - 可変長引数」に、リダイレクトを残さずに移動しました)
編集の要約なし
 
(同じ利用者による、間の1版が非表示)
5行目: 5行目:
== 可変長引数テンプレート ==
== 可変長引数テンプレート ==
この方法は、最も簡潔な方法である。<br>
この方法は、最も簡潔な方法である。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  template<typename... T>
  template<typename... T>
  int sum(T... args)
  int sum(T... args)
17行目: 17行目:
     return s;
     return s;
  }
  }
  </source>
  </syntaxhighlight>
  <source lang="c++">
<br>
  <syntaxhighlight lang="c++">
  // 使用方法
  // 使用方法
  std::cout << sum();        // 0
  std::cout << sum();        // 0
24行目: 25行目:
  std::cout << sum(1, 2);    // 3
  std::cout << sum(1, 2);    // 3
  std::cout << sum(1, 2, 3); // 6
  std::cout << sum(1, 2, 3); // 6
  </source>
  </syntaxhighlight>
<br>
<br>
パラメータパックT... argsは配列ではないため、for文で処理することはできないが、<br>
パラメータパックT... argsは配列ではないため、for文で処理することはできないが、<br>
43行目: 44行目:
sum(2, 3)は再帰呼び出しとなるため、再びテンプレート関数(2)呼び出され、先程と同じ手順による展開が行われる。(return 2 + sum(3);)<br>
sum(2, 3)は再帰呼び出しとなるため、再びテンプレート関数(2)呼び出され、先程と同じ手順による展開が行われる。(return 2 + sum(3);)<br>
最後に、sum(3)がテンプレート関数(1)に適用される形となる。<br>
最後に、sum(3)がテンプレート関数(1)に適用される形となる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // (1)
  // (1)
  template<typename First>
  template<typename First>
63行目: 64行目:
     std::cout << v;  // 6
     std::cout << v;  // 6
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
これら一連の展開が完了すると、およそ以下のような実行コードが形成されることになる。<br>
これら一連の展開が完了すると、およそ以下のような実行コードが形成されることになる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  int sum(int c) { reutrn c; }
  int sum(int c) { reutrn c; }
  int sum(int b, int c) { reutrn b + sum(c); }
  int sum(int b, int c) { reutrn b + sum(c); }
75行目: 76行目:
     int v = sum(1, 2, 3);
     int v = sum(1, 2, 3);
  }
  }
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


81行目: 82行目:
若干趣旨が異なるが、初期化子リストを受け取るためのクラスstd::initializer_listを活用する方法もある。<br>
若干趣旨が異なるが、初期化子リストを受け取るためのクラスstd::initializer_listを活用する方法もある。<br>
ソースコードの役割を明確化したり、可読性を高めたりするための用途として活用できる。<br>
ソースコードの役割を明確化したり、可読性を高めたりするための用途として活用できる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  int sum(std::initializer_list<int> list)
  int sum(std::initializer_list<int> list)
  {
  {
98行目: 99行目:
     std::cout << v; // 6
     std::cout << v; // 6
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  return contain(extention, {"cpp", "cc", "cp"});
  return contain(extention, {"cpp", "cc", "cp"});
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


== 可変個数の実引数 ==
== 可変個数の実引数 ==
C言語の仕組みを利用する方法もある。<br>
C言語の仕組みを利用する方法もある。<br>
この方法は、[[可変長引数を実現する方法(C)|こちらのページ]]を参照すること。<br>
この方法は、[[C言語の基礎 - 可変長引数|C言語の基礎 - 可変長引数]]を参照すること。<br>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]

2021年11月24日 (水) 17:57時点における最新版

概要

C++で可変長の引数を使用する場合は、テンプレートを用いる必要がある。


可変長引数テンプレート

この方法は、最も簡潔な方法である。

 template<typename... T>
 int sum(T... args)
 {
    int s = 0;
    for (int i : std::initializer_list<int>{args...})
    {
       s += i;
    }
 
    return s;
 }


 // 使用方法
 std::cout << sum();        // 0
 std::cout << sum(1);       // 1
 std::cout << sum(1, 2);    // 3
 std::cout << sum(1, 2, 3); // 6


パラメータパックT... argsは配列ではないため、for文で処理することはできないが、
パラメータパックを初期化リストstd::initializer_listに展開することで、for文を用いた可変長引数の操作が可能になる。

再帰呼び出しによるパラメータパックの展開
この方法は、より伝統的な方法である。

テンプレート関数(2)が処理の肝である。
テンプレート内のtypename... Restという記述により、可変長のテンプレートパラメータを受け取ることが可能になる。
また、第2引数Rest... restという記述により、関数呼び出し側の第2引数以降に指定した実引数は、全てこのrestに集約される。
これらは、パラメータパックと呼ばれる。(Rest : テンプレートパラメータパック、rest : 関数パラメータパック)

集約された複数の引数はRest...という記述で展開する。(アンパック)
以下のサンプルコードでは、sum(1, 2, 3)という記述は、引数firstに1、引数restに2と3という形に展開される。
よって、sum(1, 2, 3)という呼び出しは、関数内ではreturn 1 + sum(2, 3);という展開が行われる。

sum(2, 3)は再帰呼び出しとなるため、再びテンプレート関数(2)呼び出され、先程と同じ手順による展開が行われる。(return 2 + sum(3);)
最後に、sum(3)がテンプレート関数(1)に適用される形となる。

 // (1)
 template<typename First>
 int sum(First first)
 {
    return first;
 }
 
 // (2)
 template<typename First, typename... Rest>
 int sum(First first, Rest... rest)
 {
    return first + sum(rest...);
 }
 
 int main(int argc, char *argv[])
 {
    int v = sum(1, 2, 3);
    std::cout << v;  // 6
 }


これら一連の展開が完了すると、およそ以下のような実行コードが形成されることになる。

 int sum(int c) { reutrn c; }
 int sum(int b, int c) { reutrn b + sum(c); }
 int sum(int a, int b, int c) { reutrn a + sum(b, c); }
 
 int main()
 {
    int v = sum(1, 2, 3);
 }



初期化子リスト

若干趣旨が異なるが、初期化子リストを受け取るためのクラスstd::initializer_listを活用する方法もある。
ソースコードの役割を明確化したり、可読性を高めたりするための用途として活用できる。

 int sum(std::initializer_list<int> list)
 {
    int sum = 0;
    for (int i : list)
    {
       sum += i;
    }
 
    return sum;
 }
 
 void test()
 {
    int v = sum({1, 2, 3});
    std::cout << v; // 6
 }


 return contain(extention, {"cpp", "cc", "cp"});



可変個数の実引数

C言語の仕組みを利用する方法もある。
この方法は、C言語の基礎 - 可変長引数を参照すること。