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