如何写一个可接受任意数量参数的函数

3 篇文章 0 订阅

在 c++11之前,编写带有任意数量参数的函数的唯一方法是使用可变参数函数,最有名的要数 C Runtime Library 的 printf (...)。

 如果您曾经使用这种方法编写过代码,你就会知道这种方法有多么麻烦。 除了类型不安全之外,还需要纠正一些错误。而且,每次使用都要小心翼翼,说不定哪里就出错了。所以,下面给大家介绍一个超cool的东西,可变参数模板。


可变参数模板

直接来看个例子,最经典的就是一个add函数的实现了,它将所有参数加在一起:

 template <typename T> 
 T  add(T value)
 {
      return value;
 }
 template <typename T, typename... Ts>
 T  add(T head, Ts... rest) 
 {
      return head + add(rest...); 
 }

当你写下如下的两个调用时:

auto test1 = add(1,2,3,4,5);
auto test2 = add("what's"s, " up"s, "!"s);

std::cout << test1 << std::endl;
std::cout << test2 << std::endl;

它会输出:

15

what's up!


发生了什么

这看起来很像递归不是吗。其实不是,来看下为什么。

当你写下这样的函数的时候,编译器会为你生成以下函数:

    template<>
    int add<int, int, int, int, int>(int head, int __rest1, int __rest2, int __rest3, 
    int __rest4)
    {
      return head + add(__rest1, __rest2, __rest3, __rest4);
    }

    template<>
    int add<int, int, int, int>(int head, int __rest1, int __rest2, int __rest3)
    {
      return head + add(__rest1, __rest2, __rest3);
    }

    template<>
    int add<int, int, int>(int head, int __rest1, int __rest2)
    {
      return head + add(__rest1, __rest2);
    }
    
    template<>
    int add<int, int>(int head, int __rest1)
    {
      return head + add(__rest1);
    }

    template<>
    int add<int>(int value)
    {
      return value;
    }

当你在你的程序调用add函数时,在编译阶段,编译器会为你生成每个调用对应的函数,包括参数的个数和类型。其实上面的结果告诉我们,是函数重载在起作用。注意了哦,是函数重载,可不是递归。


更多

虽然在上面的例子它很好的运行了,并且给出了我们预期的结果。但是,假如我们变化一下调用的方式呢?

add("what's"s, ' ', "up!"s);

上面的例子中,我们在中间加了一个char类型的 '  ',因为std::string是允许我们将一个char + std::string或者std::string + char这样的调用的,我们可以将一个char类型字符的拼接到一个string类型的字符串,形成一个更长的字符串。所以我们这样应该也是可以的。但是当我写下这样的代码,按下F5,编译器却报给了我一个错误。下面是报错截图:

发生了什么呢?再看一下我们编译器为我们特化的函数,要注意到,每个函数的返回类型,T,都是和第一个参数的类型相同,所以当我特化到add(char, std::string)的时候,它的返回类型是char,但是实际上我们的函数内部返回的却是一个string类型的东西,这样就会造成返回类型不匹配。怎么解决呢?


怎么解决

还记得我们的auto吗?哈哈,这个好东西又派上用场了,我们需要将我们的add函数返回类型声明的auto,这样,编译器就会自动推导出一个正确的返回类型。

 template <typename T> 
 auto  add(T value)
 {
      return value;
 }

 template <typename T, typename... Ts>
 auto  add(T head, Ts... rest) 
 {
      return head + add(rest...); 
 }

这样,当你再这样调用的时候:

add("what's"s, ' ', "up!"s);

It works!

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值