質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

16172閲覧

可変引数の引数の数を取得する。

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/06/02 13:10

C++

1int func(int count, ...){ 2 int sum = 0; 3 va_list ap; 4 5 va_start(ap, count); 6 for(int i = 0; i < count; i++) 7 sum += va_arg(ap, int); 8 va_end(ap); 9 return sum; 10}

動作は確認していません。適当に作りました。間違っているかもしれません。
func関数を呼び出す際に、countで引数の個数を入力する必要があります。

めんどうです。

最初に引数の個数をユーザー側で入力せずに、引数の個数をカウントするのはどうやればできるのでしょうか??
すなわち、func関数内でcountを算出するということです!

どなたか教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

すでに variadic template を用いた回答が出ていますが、引数の数をカウントするだけであれば再帰をせずとも sizeof... を使えば一発で出ます。

template<class... T> int count_arguments(T... args){ return sizeof...(args); } #include <iostream> int main(void) { std::cout << count_arguments(1,2,3) << std::endl; return 0; }

もしも処理系が C++17 に対応しているならば、引数を足し合わせる操作に関してもテンプレートの再帰などといった回りくどいことをしなくても fold expression と呼ばれる形式が利用可能です。

template<class... T> int sum(T... args) { return (args+...); } #include <iostream> int main(void) { std::cout << sum(1,2,3) << std::endl; return 0; }

ただ、 C++17 はまだ非対応の処理系が多いかもしれませんね。

投稿2017/06/02 14:01

SaitoAtsushi

総合スコア5454

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/02 14:04

C++17 ! 最新はもうそこまで行ってるんですか!
guest

0

ベストアンサー

すなわち、func関数内でcountを算出するということです!

残念ながら、不可能です。

可変長引数を取る関数に任意個の実引数を渡すには、番兵(sentinel)を用いる実装方式があります。下記コードでは正数のみを有効データとみなしています。

C

1int func(int init, ...) { 2 int sum = init; 3 va_list ap; 4 5 va_start(ap, init); 6 for (;;) { 7 int val = va_arg(ap, int); 8 if (val < 0) 9 break; 10 sum += val; 11 } 12 va_end(ap); 13 return sum; 14} 15 16int main() { 17 int sum = func(1, 2, 3, -1); 18 printf("%d\n", sum); 19} 20

どうしても「個数」を直接取得したい場合、強引に似たようなことを実現できなくもありません。下記コードはC99/C11でしか動作しませんが、countを自動計算させています。(参考:Cで可変長引数のみを取る関数を作る

C

1int func_impl(int count, ...) { 2 int sum = 0; 3 va_list ap; 4 5 va_start(ap, count); 6 for(int i = 0; i < count; i++) 7 sum += va_arg(ap, int); 8 va_end(ap); 9 return sum; 10} 11 12#define count_args(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int)) 13#define func(...) func_impl(count_args(__VA_ARGS__), __VA_ARGS__) 14 15int main() { 16 int sum = func(1, 2, 3); 17 printf("%d\n", sum); 18}

おまけ:最新のC++機能をつかうと下記のように書くこともできます。(もはや"個数"が不要なのですが、必要ならsizeof...(args)で取得可能です)

C++

1#include <stdio.h> 2 3template<typename... Ts> 4int func(Ts... args) { 5 //printf("count=%zu\n", sizeof...(args)); 6 return (args + ...); 7} 8 9int main() { 10 int sum = func(1, 2, 3); 11 printf("%d\n", sum); 12}

投稿2017/06/02 13:42

編集2017/06/02 13:58
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/02 14:05

なるほどです! Cは無理なんですね! わかりました。 C++でやってみます。
yohhoy

2017/06/02 14:11

ちょっとした補足:どちらも ... を使うので紛らわしいのですが、C言語の「可変長引数(variadic function)」とC++言語の「可変引数テンプレート(variadic templates)」は全くの別物です。C言語スタイルの機能はC++言語でもそのまま使えます(つまりC++には2種類ある)。
strike1217

2017/06/02 14:20

あ、「C++にはやり方が2種類ある」という事ですね!
SaitoAtsushi

2017/06/02 14:55

variadic template を使う方が安全ではあるので特に理由がなければ使うのが望ましいと思います。 C との互換性などの理由で古い可変長引数の仕組みは残っていますが、 `va_arg` でプログラマが型を指定するときに間違っていてもコンパイラが捕捉してエラーを出すということがしにくい (ひょっとすると頑張ってエラーにする処理系もあるのかもしれませんが) ので間違ったことをしたときに不可解な実行時エラー、あるいはクラッシュを引き起こす可能性があります。 variadic template はコンパイル時に型が確定しますし、間違っていればコンパイルエラーになるだけです。 ただ、型ごとに、引数の個数ごとに関数が実体化されるのでバイナリサイズがちょっと大きくなったりするということはあるかもしれません。 よほどリソースの限られたマイコンとかでなければ気にするほどではないと思いますが……。
strike1217

2017/06/02 14:58

variadic templateの使用をおすすめしているのですね! 分かりました。
guest

0

こんにちは。

C言語機能の範疇では無理です。
しかし、C++11以降で使えるようになったValidac Templateを使えば可能です。「可変長テンプレート」で検索すると使い方の解説がそこそこ出てきます。
ただ、テンプレート+再帰なのでなかなかハードです。でも、使えるようになると結構便利です。

引数の数を数えるだけなら、次のコードでカウントできます。

C++

1#include<iostream> 2 3unsigned count() 4{ 5 return 0; 6} 7 8template<typename tFirst, typename... tTypes> 9unsigned count(tFirst const&, tTypes const&... iRef) 10{ 11 return count(iRef...)+1; 12} 13 14struct Foo { }; 15 16int main() 17{ 18 std::cout << count(1, 2, 3, 4, 5) << "\n"; 19 std::cout << count("abc", Foo()) << "\n"; 20}

でも、これだけでは役に立たないです。まだ結構頑張らないと使えるようになりません。

投稿2017/06/02 13:51

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/02 14:04

可変長テンプレートというものがあるのですね!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問