「C++の基礎 - 可変長引数」の版間の差分
細 (Wiki がページ「可変長引数を実現する方法(C++)」を「C++の基礎 - 可変長引数」に、リダイレクトを残さずに移動しました) |
編集の要約なし |
||
(同じ利用者による、間の1版が非表示) | |||
5行目: | 5行目: | ||
== 可変長引数テンプレート == | == 可変長引数テンプレート == | ||
この方法は、最も簡潔な方法である。<br> | この方法は、最も簡潔な方法である。<br> | ||
< | <syntaxhighlight lang="c++"> | ||
template<typename... T> | template<typename... T> | ||
int sum(T... args) | int sum(T... args) | ||
17行目: | 17行目: | ||
return s; | return s; | ||
} | } | ||
</ | </syntaxhighlight> | ||
< | <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 | ||
</ | </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> | ||
< | <syntaxhighlight lang="c++"> | ||
// (1) | // (1) | ||
template<typename First> | template<typename First> | ||
63行目: | 64行目: | ||
std::cout << v; // 6 | std::cout << v; // 6 | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
これら一連の展開が完了すると、およそ以下のような実行コードが形成されることになる。<br> | これら一連の展開が完了すると、およそ以下のような実行コードが形成されることになる。<br> | ||
< | <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); | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
81行目: | 82行目: | ||
若干趣旨が異なるが、初期化子リストを受け取るためのクラスstd::initializer_listを活用する方法もある。<br> | 若干趣旨が異なるが、初期化子リストを受け取るためのクラスstd::initializer_listを活用する方法もある。<br> | ||
ソースコードの役割を明確化したり、可読性を高めたりするための用途として活用できる。<br> | ソースコードの役割を明確化したり、可読性を高めたりするための用途として活用できる。<br> | ||
< | <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 | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
< | <syntaxhighlight lang="c++"> | ||
return contain(extention, {"cpp", "cc", "cp"}); | return contain(extention, {"cpp", "cc", "cp"}); | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><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言語の基礎 - 可変長引数を参照すること。