变长参数
参数个数类型不确定的函数,
c语言例子如下
Technically to use variable number of arguments in C you include stdarg.h. From that you'll get the va_list type as well as three functions that operate on it called va_start(), va_arg() and va_end().
/*c语言的variadic function*/
#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;
}
c++
// myPrintf.cpp
#include <iostream>
void myPrintf(const char* format){ // (3)
std::cout << format;
}
template<typename T, typename ... Args>
void myPrintf(const char* format, T value, Args ... args){ // (4)
for ( ; *format != '\0'; format++ ) { // (5)
if ( *format == '%' ) { // (6)
std::cout << value;
myPrintf(format + 1, args ... ); // (7)
return;
}
std::cout << *format; // (8)
}
}
int main(){
myPrintf("\n"); // (1)
myPrintf("% world% %\n", "Hello", '!', 2011); // (2)
myPrintf("\n");
}
std::unique
template <typename T, typename ... Args>
std::unique_ptr<T> make_unique(Args&& ... args){
return std::unique_ptr<T>(new T(std::forward<Args>(args) ... ));
}
Fold Expressions
Fold Expressions 之前
//如果没有这个单参的重载,递归没办法结束
template<typename T>
T add(const T& arg)
{
return arg;
}
template<typename T, typename... ARGS>
T add(const T& arg, const ARGS&... args)
{
return arg + add(args...);
}
int main()
{
return add(1, 2u, 3u);
}
//有了Fold Expressions之后
template<typename... ARGS>
auto add(const ARGS&... args)
{
return (args + ...);
}
int main()
{
return add(1, 2u, 3u);
}
结论
variadic function 类型不安全,编译不报错,出很多运行时错误。所以能不用就不用。不过如果比较关心二进制文件的大小,或者指令缓存很敏感,那么可以用c-style variadic function( C-style variadic functions produce less code when compiled than C++-style variadic templates, so if you're concerned about binary size or instruction cache pressure, you should consider implementing your functionality with varargs instead of as a template.)
在c++编程中,保留c-stype variadic function的唯一原因就是向后兼容。需要用到变长参数时,c++的选择应该是variadic template。
附录
c-style的变长参数函数还有个用处,如下所示:
(It is remarkably convenient that in C++ variadic functions can have no regular parameters. Also a variadic function is the least fit candidate within overload resolution (if a function call has at least one argument). Like any other function a variadic one can be only declared but never called:)
template <class T>
struct HasFoo
{
private:
template <class U, class = decltype(std::declval<U>().foo())>
static void detect(const U&);
static int detect(...);
public:
static constexpr bool value =
std::is_same<void, decltype(detect(std::declval<T>()))>::value;
};
c++14,可以写成下面这样,更容易理解一些
template <class T>
struct HasFoo
{
private:
template <class U, class = decltype(std::declval<U>().foo())>
static constexpr bool detect(const U*)
{
return true;
}
template <class U>
static constexpr bool detect(...){
return false;
}
public:
static constexpr bool value = detect<T>(nullptr);
};