C++11 可变参数模板中的 va_arg() 是什么?
What's va_arg() in C++11 variadic template?
我读过一些关于这个新的C++11特性的文章,但我并没有完全理解(我是C++的新手)。如何访问特定的参数,就像在C中使用stdarg.h
中的va_arg
一样?
template <typename ... Args>
void f(Args ... args)
{
for(size_t i = 0; i < sizeof ...(args); i++)
{
// obviously, args...[i] didn't work...
}
}
问题是TYPE var = args[c];
,您为TYPE
编写了什么?每个i
都有不同的类型,所以不能像这样使用for
循环。
一般来说,通常的方法是使用递归。
void f() { } //end loop
template<class FirstType, typename...Args>
void f(FirstType&& first, Args&&...rest) {
//do loop body
loop_body(std::forward<FirstType>(first)...)
//do next "iteration"
f(std::forward<Args>(rest)...);
}
还有一种不用递归的方法,但它更高级:
template<typename...Args>
void f(Args&&...args) {
typedef int[] for_each;
for_each{((void)( loop_body(std::forward<Args>(args)) ),0)...,0};
}
最后,如果你真的想通过索引访问一个:
//note that "i" must be a compile time constant
auto var = std::get<i>(std::tie(std::forward<Args>(args)...));
typedef int[]
代码非常奇怪,所以我将把它放在这里我们想调用函数
loop_body(std::forward<Args>(args))...;
,但不幸的是,参数包只能在某些上下文中扩展,而这不是其中之一。最简单、最明显的解决方案是将所有这些调用的结果传递给一个什么都不做的函数:do_nothing(loop_body(std::forward<Args>(args))...)
,但不幸的是,这对于void
返回类型来说失败了,因为您无法实例化一个void
来传递给do_nothing
。更糟糕的是,它可能会以错误的顺序调用每个函数。将void
表达式"转换"为其他表达式的一种方法是使用逗号运算符,(func(), 0)
执行func
,然后"返回"0
更糟糕的是,由于我不理解的原因,
f(vs)...,0;
和(f(vs),0)...,0;
都是扩展参数包的有效上下文。然而,type array[] = {vs...}
是一个有效的上下文。因此,现在我们有了一种方法,可以将此上下文与具有返回值的表达式结合起来:int array[] = {(f(vs),0)...};
,它很有效!大多数情况下如果参数包的类型为零(是的,这是有效的。永远不要忘记它。),那么这将导致编译器错误。所以我们必须在末端再加一个零,这样就总是至少有一个元素:
int array[] = {(f(vs),0)..., 0};
。此外,大多数编译器警告说,array
是一个未使用的变量。绕过该警告的一种方法是将该类型设为临时类型。int a = (expr);
是本地的,但(int)(expr)
创建了一个未命名的临时。所以我们想要(int []){(f(vs),0)..., 0};
。由于我记不起的原因,这个(int[])
通常隐藏在typedef后面。最后,由于某些类可能会重载逗号运算符,因此最安全的做法是将函数强制转换为void
:int array[] = {((void)(f(vs)),0)..., 0};
无关,我过去曾考虑过这个宏,它更多地隐藏了丑陋的细节。但我觉得有一个缺点我忽略了,否则它会更常见。
#define FOREACH_VARIADIC(EXPR) (int[]){((void)(EXPR),0)...,0}
template<typename...Args>
void f(Args&&...args) {
FOREACH_VARIADIC(loop_body(std::forward<Args>(args)));
}
接受的答案非常好,但这里有一个使用C++14通用lambdas:的想法
template <typename F>
void variadic_for_each(F) {}
template <typename F, typename Head, typename... Tail>
void variadic_for_each(Head&& head, Tail&&... tail, F f)
{
f(std::forward<Head>(head));
variadic_for_each(std::forward<Tail>(tail)..., f);
}
示例用法:
template <typename... Ts>
void myFunc(Ts&&... vs)
{
variadic_for_each(std::forward<Ts>(vs)..., [](auto&& v)
{
// loop body
});
}
相关文章:
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么