Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中参数的可变数量+;?_C++_Variadic Functions - Fatal编程技术网

C++ C+中参数的可变数量+;?

C++ C+中参数的可变数量+;?,c++,variadic-functions,C++,Variadic Functions,如何编写一个接受可变数量参数的函数?这是否可能,如何实现?唯一的方法是使用C风格的变量参数,如前所述。请注意,这不是一个推荐的做法,因为它不是类型化和容易出错的。< P> C风格的变量函数在C++中支持。 但是,大多数C++库使用一个替代的习惯用法,而 C 'Prtuf函数采用变量变量,> C++ +CUT/对象使用>P>,正如其他人所说的,C风格VARARGS。但是,您也可以使用默认参数执行类似操作。您可能不应该这样做,并且您可以用更安全、更简单的方式执行您想执行的操作。从技术上讲,要在C语言

如何编写一个接受可变数量参数的函数?这是否可能,如何实现?

唯一的方法是使用C风格的变量参数,如前所述。请注意,这不是一个推荐的做法,因为它不是类型化和容易出错的。

< P> C风格的变量函数在C++中支持。
<>但是,大多数C++库使用一个替代的习惯用法,而 C 'Prtuf函数采用变量变量,> C++ +CUT/<代码>对象使用>P>,正如其他人所说的,C风格VARARGS。但是,您也可以使用默认参数执行类似操作。

您可能不应该这样做,并且您可以用更安全、更简单的方式执行您想执行的操作。从技术上讲,要在C语言中使用可变数量的参数,可以使用stdarg.h。从中您将得到
va_列表
类型以及对其进行操作的三个函数,分别称为
va_start()
va_arg()
va_end()

#包括
int maxof(int n_args,…)
{
va_列表ap;
va_启动(ap,n_参数);
int max=va_arg(ap,int);
对于(int i=2;i max)max=a;
}
va_端(ap);
返回最大值;
}

如果你问我,这真是一团糟。它看起来很糟糕,不安全,而且它充满了技术细节,与您在概念上试图实现的目标无关。相反,考虑使用重载或继承/多态性,Builder模式(如<代码>运算符> P>没有标准C++方式,不诉诸C样式VARARGS(<代码>…<代码>)。 当然,根据上下文的不同,有一些默认参数的“外观”类似于可变数量的参数:

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

// other code...

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

所有四个函数调用的
myfunc
的参数数量都不同。如果没有给出参数,则使用默认参数。但是,请注意,您只能忽略尾随参数。例如,如果您知道将提供的参数数量范围,则无法忽略
i
并仅给出
j
,您总是可以使用一些函数重载,例如

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

等…

除了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);
模板空f(std::vector const&);
std::vector my_args;
我的参数。向后推(1);
我的_args.push_back(2);
f(我的参数);
通过这种方式,您将获得类型安全性,并且这些可变参数的逻辑意义将是显而易见的


当然,这种方法可能会有性能问题,但你不应该担心它们,除非你确定自己无法为此付出代价在C++ 11中,C++有一种方法来实现可变参数函数的真正优雅和类型安全的方法。Bjarne自己在

中给出了一个很好的例子。
P>个人认为,这样的代码是如此优雅,以至于我在C++中甚至不去考虑变量参数函数,直到编译器支持C++ 11变量参数模板。

< P>你可能需要重载或默认参数。用缺省参数定义相同的函数:

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 );
}
这将允许您使用以下四种不同调用之一调用该方法:

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

…或者您可以从C中查找v_参数调用约定。

如果所有参数都是常量且类型相同,我们也可以使用初始值设定项列表。

在C++11中,您有两个新选项,如“备选方案”部分中的参考页所述:

  • 可变模板还可用于创建采用可变数量 争论。它们通常是更好的选择,因为它们不限制 参数的类型不执行整数和浮点提升,以及 是类型安全的。(从C++11开始)
  • 如果所有变量参数共享一个公共类型,则std::initializer\u列表提供 访问变量参数的方便机制(尽管语法不同)
下面是一个显示这两种备选方案()的示例:

示例()中变量函数的结果如下所示:

void func(T,Args…[T=int,Args=]:1
void func(T,Args…[T=double,Args=]:2.5
void func(T,Args…[T=char,Args=]:a
void func(T)[T=std::basic_string]:您好
在VisualStudio中,您可以使用

更新C++11之前的版本

C++11之前版本的替代方案可能是或另一种:

#包括
#包括
#包括
模板
void func1(标准::向量向量)
{
对于(typename std::vector::iterator iter=vec.begin();iter!=vec.end();++iter)
{
std::cout在c++11中,您可以执行以下操作:

void foo(const std::list<std::string> & myArguments) {
   //do whatever you want, with all the convenience of lists
}

foo({"arg1","arg2"});
void foo(const std::list&myArguments){
//你想做什么就做什么,尽可能方便地列出清单
}
foo({“arg1”、“arg2});
列出初始值设定项FTW!

intfun(intn_参数,…){
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;
   }
}
int*p=&n_参数; int s=sizeof(int); p+=s+s-1; 对于(int i=0;i
普通版

C++17解决方案:完整类型安全+良好的调用语法 由于在C++11中引入了可变模板,在C++17中引入了折叠表达式,因此可以在调用者站点定义一个模板函数,该函数可以像调用可变函数一样调用,但其优点是:

  • 具有很强的类型安全性
  • 在不使用参数数量的运行时信息或不使用“stop”参数的情况下工作
下面是一个混合参数类型的示例

template<class... Args>
void print(Args... args)
{
    (std::cout << ... << args) << "\n";
}
print(1, ':', " Hello", ',', " ", "World!");
模板
无效打印(Args…Args)
{

(std::cout使用可变模板,例如再现JavaScript中的
console.log

Console console;
console.log("bunch", "of", "arguments");
console.warn("or some numbers:", 1, 2, 3);
console.error("just a prank", "bro");
文件名,例如
js_console.h

#include <iostream>
#include <utility>

class Console {
protected:
    template <typename T>
    void log_argument(T t) {
        std::cout << t << " ";
    }
public:
    template <typename... Args>
    void log(Args&&... args) {
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }

    template <typename... Args>
    void warn(Args&&... args) {
        cout << "WARNING: ";
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }

    template <typename... Args>
    void error(Args&&... args) {
        cout << "ERROR: ";
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }
};
#包括
#包括
类控制台{
受保护的:
模板
无效日志参数(T){
std::cout

#include <iostream> #include <string> #include <cstdarg> void simple_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); while (*fmt != '\0') { if (*fmt == 'd') { int i = va_arg(args, int); std::cout << i << '\n'; } else if (*fmt == 's') { char * s = va_arg(args, char*); std::cout << s << '\n'; } ++fmt; } va_end(args); } int main() { std::string str1( "Hello" ), str2( "world" ); simple_printf("dddd", 10, 20, 30, 40 ); simple_printf("ss", str1.c_str(), str2.c_str() ); return 0 ; }

void foo(const std::list<std::string> & myArguments) {
   //do whatever you want, with all the convenience of lists
}

foo({"arg1","arg2"});
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;
   }
}
template<class... Args>
void print(Args... args)
{
    (std::cout << ... << args) << "\n";
}
print(1, ':', " Hello", ',', " ", "World!");
#include <type_traits> // enable_if, conjuction

template<class Head, class... Tail>
using are_same = std::conjunction<std::is_same<Head, Tail>...>;

template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
void print_same_type(Head head, Tail... tail)
{
    std::cout << head;
    (std::cout << ... << tail) << "\n";
}
print_same_type("2: ", "Hello, ", "World!");   // OK
print_same_type(3, ": ", "Hello, ", "World!"); // no matching function for call to 'print_same_type(int, const char [3], const char [8], const char [7])'
                                               // print_same_type(3, ": ", "Hello, ", "World!");
                                                                                              ^
Console console;
console.log("bunch", "of", "arguments");
console.warn("or some numbers:", 1, 2, 3);
console.error("just a prank", "bro");
#include <iostream>
#include <utility>

class Console {
protected:
    template <typename T>
    void log_argument(T t) {
        std::cout << t << " ";
    }
public:
    template <typename... Args>
    void log(Args&&... args) {
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }

    template <typename... Args>
    void warn(Args&&... args) {
        cout << "WARNING: ";
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }

    template <typename... Args>
    void error(Args&&... args) {
        cout << "ERROR: ";
        int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
        cout << endl;
    }
};
#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);
}
// spawn: allocate and initialize (a simple function)
template<typename T>
T * spawn(size_t n, ...){
  T * arr = new T[n];
  va_list ap;
  va_start(ap, n);
  for (size_t i = 0; i < n; i++)
    T[i] = va_arg(ap,T);
  return arr;
}

auto arr = spawn<float> (3, 0.1,0.2,0.3);