如何对传递给可变参数宏的可变参数求和
How to sum variadic arguments passed in to a variadic macro?
我想要一个程序来定义一个宏,该宏可以计算参数的数量并将它们传递给函数sum
该函数对参数的值求和并返回总数。我设法在 GCC 上做到了这一点,但我想在 Visual C++ 14 上实现它。
#include "stdafx.h"
#include <iostream>
#include <cstdarg>
#define ELEVENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
#define COUNT_ARGUMENTS(...) ELEVENTH_ARGUMENT(dummy, ## __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define SUM(...) sum(ELEVENTH_ARGUMENT(dummy, ## __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
int sum(int n, ...) {
int sz{ n };
va_list ap;
va_start(ap, n);
int tmp{};
while (--sz)
tmp += va_arg(ap, int);
va_end(ap);
return tmp;
}
int main() {
std::cout << COUNT_ARGUMENTS(4,57,22,10,5,6,2,8,68,24,24,86,89,89,96,86) << std::endl; // 1
std::cout << SUM(5, 57, 4, 5) << std::endl; // 0
std::cout << COUNT_ARGUMENTS(5, 57, 10) << std::endl;// 1
std::cout << std::endl;
std::cin.get();
}
我不知道我的代码出了什么问题,它总是给我总和是 0。
不要使用可变参数宏。 Visual C++ 14(或 2015)是符合 C++11/14 的编译器。 这意味着它支持可变参数模板。 您可以轻松递归参数包以获取参数的总和,并且可以使用 sizeof...
完成计数。 这使您可以将count
写为
template<typename... Args>
auto count(Args&&...)
{
return sizeof...(Args);
}
然后sum
可以写成
// base case
template<typename T>
auto sum(T&& first)
{
return first;
}
// multiple parameters case
template<typename T, typename... Args>
auto sum(T&& first, Args&&... rest)
{
return first + sum(rest...);
}
在
int main()
{
std::cout << count(3,4,5) << "n";
std::cout << sum(3,4,5);
}
指纹
3
12
你可以在这个现场的例子中看到。
正如HolyBlackCat所建议的那样,您可以使用虚拟数组技巧来避免使用递归。 那会给你sum
一个看起来像
template <typename ...P>
auto sum(const P &... params)
{
using dummy_array = int[];
std::common_type_t<P...> ret{}; // common_type_t is to find the appropriate type all of the parameter can be added to
(void)dummy_array{(void(ret += params), 0)..., 0}; // add the parameter to ret, discard it's result, return the value of 0 for the array element
return ret;
}
请注意,这可能不适用于所有类型,如此处所示 std::valarray
. 将其更改为
template <typename T, typename ...P>
auto sum(T first, P&&... rest) // copy the first parameter to use it as the accumulator
{
using dummy_array = int[];
(void)dummy_array{(void(first += params), 0)..., 0}; // add the parameter to ret, discard it's result, return the value of 0 for the array element
return first;
}
应该更正确,尽管它可能会进一步改进(欢迎建议/编辑)
如果您可以使用 C++17 投诉编译器,那么可以使用折叠表达式进一步简化sum
例如
template<typename... Args>
auto sum(Args&&... rest)
{
return (rest + ...);
}
补充@NathanOliver,如果你想使用没有递归的可变参数模板,std::initializer_list
和std::common_type
在 C++11 中都可用,允许你这样做:
template <typename... Args,
typename T = typename std::common_type<Args...>::type>
T sum(Args&&... args) {
std::initializer_list<T> l{args...};
return std::accumulate(l.begin(), l.end(), T{});
}
编辑:请注意,此解决方案将允许在可隐式转换为通用类型的所有类型上调用 sum(这就是common_type
所做的)。
例如:
sum(1, 2, 3) // Ok, all ints
sum(1, 2, true) // Ok, bool converts to int
sum(1, 2, 3.) // Error, int to double is a narrowing conversion
相关文章:
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 从变长参数列表中提取std::string