355

可変数の引数を受け入れる関数を作成するにはどうすればよいですか? これは可能ですか?

4

18 に答える 18

184

あなたはおそらくそうすべきではありません、そしてあなたはおそらくあなたがしたいことをより安全でより簡単な方法で行うことができます。技術的には、Cで可変数の引数を使用するには、stdarg.hをインクルードします。そこから、タイプと、それを操作する、、およびva_listと呼ばれる3つの関数を取得します。va_start()va_arg()va_end()

#include<stdarg.h>

int maxof(int n_args, ...)
{
    va_list ap;
    va_start(ap, n_args);
    int max = va_arg(ap, int);
    for(int i = 2; i <= n_args; i++) {
        int a = va_arg(ap, int);
        if(a > max) max = a;
    }
    va_end(ap);
    return max;
}

あなたが私に尋ねるなら、これは混乱です。見た目は悪く、安全ではなく、概念的に達成しようとしていることとは関係のない技術的な詳細が満載です。代わりに、オーバーロードまたは継承/ポリモーフィズム、ビルダーパターン(operator<<()ストリームの場合のように)またはデフォルトの引数などを使用することを検討してください。これらはすべてより安全です。あなたがあなたの足を吹き飛ばす前にあなた。

于 2009-11-01T18:38:42.527 に答える
21

C++11 では、可変引数テンプレートを実行する方法があり、これにより、可変引数関数を使用するための非常に洗練された型安全な方法が実現します。Bjarne 自身がC++11FAQ可変引数テンプレートを使用した printfの良い例を挙げています。

個人的には、これは非常に洗練されていると考えているため、コンパイラが C++11 可変引数テンプレートをサポートするまでは、C++ の可変引数関数を気にすることさえしません。

于 2009-11-01T19:39:21.983 に答える
15

C スタイルの可変引数関数は、C++ でサポートされています。

ただし、ほとんどの C++ ライブラリは別のイディオムを使用します。たとえば、'c' printf関数が変数の引数を取るのに対し、c++ coutオブジェクトは<<型の安全性と ADT に対応するオーバーロードを使用します (おそらく実装の単純さを犠牲にして)。

于 2009-11-01T18:31:21.807 に答える
14

varargs またはオーバーロードとは別に、引数を std::vector または他のコンテナー (std::map など) に集約することを検討できます。このようなもの:

template <typename T> void f(std::vector<T> const&);
std::vector<int> my_args;
my_args.push_back(1);
my_args.push_back(2);
f(my_args);

このようにして、タイプ セーフが得られ、これらの可変個引数の論理的な意味が明らかになります。

確かに、このアプローチにはパフォーマンスの問題が発生する可能性がありますが、代償を払えないことが確実でない限り、心配する必要はありません。これは、C ++への一種の「Pythonic」アプローチです...

于 2009-11-01T19:20:39.323 に答える
8

唯一の方法は、ここで説明されているように、C スタイルの変数引数を使用することです。これはタイプセーフではなく、エラーが発生しやすいため、推奨される方法ではないことに注意してください。

于 2009-11-01T18:27:32.113 に答える
7

Cスタイルのvarargs(...)を使用せずにこれを行う標準のC++の方法はありません。

もちろん、コンテキストに応じて可変数の引数のように「見える」デフォルトの引数があります。

void myfunc( int i = 0, int j = 1, int k = 2 );

// other code...

myfunc();
myfunc( 2 );
myfunc( 2, 1 );
myfunc( 2, 1, 0 );

4つの関数呼び出しはすべてmyfunc、さまざまな数の引数を使用して呼び出します。何も指定されていない場合は、デフォルトの引数が使用されます。ただし、省略できるのは末尾の引数のみであることに注意してください。たとえば、を省略iして与えるだけの方法はありませんj

于 2009-11-01T18:40:10.590 に答える
4

オーバーロードまたはデフォルトのパラメーターが必要な可能性があります-デフォルトのパラメーターを使用して同じ関数を定義します。

void doStuff( int a, double termstator = 1.0, bool useFlag = true )
{
   // stuff
}

void doStuff( double std_termstator )
{
   // assume the user always wants '1' for the a param
   return doStuff( 1, std_termstator );
}

これにより、4 つの異なる呼び出しのいずれかでメソッドを呼び出すことができます。

doStuff( 1 );
doStuff( 2, 2.5 );
doStuff( 1, 1.0, false );
doStuff( 6.72 );

... または、C の v_args 呼び出し規則を探している可能性があります。

于 2009-11-01T19:44:34.250 に答える
3

カラーコードをサポートする C++ 11

  • ジェネリックであり、すべてのデータ型で機能します
  • JavaScript のように動作しますconsole.log(1,"23")
  • 情報、警告、エラーのカラー コードをサポートします。
  • 例:
    ここに画像の説明を入力
#pragma once
#include <iostream>
#include <string>

const std::string RED = "\e[0;91m";
const std::string BLUE = "\e[0;96m";
const std::string YELLOW = "\e[0;93m";

class Logger {
private:
  enum class Severity { INFO, WARN, ERROR };

  static void print_colored(const char *log, Severity severity) {
    const char *color_code = nullptr;

    switch (severity) {
    case Severity::INFO:
      color_code = BLUE.c_str();
      break;
    case Severity::WARN:
      color_code = YELLOW.c_str();
      break;
    case Severity::ERROR:
      color_code = RED.c_str();
      break;
    }

    std::cout << "\033" << color_code << log << "\033[0m -- ";
  }

  template <class Args> static void print_args(Args args) {
    std::cout << args << " ";
  }

public:
  template <class... Args> static void info(Args &&...args) {
    print_colored("[INFO] ", Severity::INFO);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }

  template <class... Args> static void warn(Args &&...args) {
    print_colored("[WARN] ", Severity::WARN);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }

  template <class... Args> static void error(Args &&...args) {
    print_colored("[ERROR]", Severity::ERROR);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }
};

于 2021-10-10T17:23:23.763 に答える
2

提供される引数の数の範囲がわかっている場合は、次のような関数のオーバーロードをいつでも使用できます。

f(int a)
    {int res=a; return res;}
f(int a, int b)
    {int res=a+b; return res;}

等々...

于 2009-11-01T19:03:39.840 に答える
1

他の人が言っているように、Cスタイルのvarargs。ただし、デフォルトの引数を使用して同様のことを行うこともできます。

于 2009-11-01T18:33:54.050 に答える
0

今は可能です...boost any とテンプレートを使用します。この場合、引数の型を混在させることができます

#include <boost/any.hpp>
#include <iostream>

#include <vector>
using boost::any_cast;

template <typename T, typename... Types> 
void Alert(T var1,Types... var2) 
{ 

    std::vector<boost::any> a(  {var1,var2...});

    for (int i = 0; i < a.size();i++)
    {

    if (a[i].type() == typeid(int))
    {
        std::cout << "int "  << boost::any_cast<int> (a[i]) << std::endl;
    }
    if (a[i].type() == typeid(double))
    {
        std::cout << "double "  << boost::any_cast<double> (a[i]) << std::endl;
    }
    if (a[i].type() == typeid(const char*))
    {
        std::cout << "char* " << boost::any_cast<const char*> (a[i]) <<std::endl;
    }
    // etc
    }

} 


void main()
{
    Alert("something",0,0,0.3);
}
于 2019-07-10T18:14:16.030 に答える
-1

すべての引数が const で同じ型の場合、initializer_list を使用することもできます

于 2013-01-31T20:49:30.963 に答える
-2
int fun(int n_args, ...) {
   int *p = &n_args; 
   int s = sizeof(int);
   p += s + s - 1;
   for(int i = 0; i < n_args; i++) {
     printf("A1 %d!\n", *p);
     p += 2;
   }
}

プレーンバージョン

于 2017-10-26T10:27:40.443 に答える