我有一个函数,它对两个元素进行如下运算:
template <typename Type>
Type add(const Type& a, const Type& b)
{
// some logic
if(!((b >= 0) && (a > std::numeric_limits<T>::max() - b))
return a + b;
}
我想写另一个模板函数,它将以同样的方式执行一些逻辑,接受N个参数,并对所有这些参数应用前一个函数,例如:
template <typename... Args>
idk_how_type_need add_n_elements(Args... args)
{
return //here i want smth like -> add(add(arg0, arg1), add(arg2, arg3)...);
}
是真实的的吗?或者也许有其他的选择?
3条答案
按热度按时间elcex8rz1#
您可以通过在
std::initializer_list
上调用std::reduce
来完成所需的操作。**注意:**此解决方案仅适用于被调用函数是可交换函数的情况,即
add(a, b) == add(b, a)
。您可以将std::reduce
替换为std::accumulate
以获得保证顺序add(add(add(a, b), c), d) ...
。如果您确实需要add(add(a, b), add(c, d)) ...
,此解决方案将不起作用!如果你想让你调用的
add
函数成为接口的一部分,你可以将其更改为:如果您的
add
函数只是一个operator+
(或另一个二元运算符),则可以使用C++17 Fold Expression。请注意,
(args + ...)
表示... (a + (b + (c + d))
,(... + args)
表示(((a + b) + c) + d) ...
。ghhaqwfi2#
嗯,用户Benjamin Buch的回答似乎是
1.对于此使用情形来说有点过于复杂
1.并且没有完全解决OP的问题,因为他想为他的N个参数应用一个函数
关于1.:对于只添加几个值,我们不需要
std::reduce
。因此,首先将值放入容器中,这里是std::initializer_list
,然后缩减此容器,这对于添加值来说太复杂了。std::reduce
有很大的优势,如果你想使用关联运算符和交换运算符并行化或矢量化大数据,习惯上首选的解决方案是使用fold expressions。我将在下面解释这一点。关于2.:这个问题根本没有解决。我将在下面展示一个解决方案,也是基于折叠表达式的。
使用fold表达式构建和。如果你看一下CPP参考here,你会发现,参数包(在你的例子
Args... args
中)是如何容易地减少的。如果你看一下那里,你会看到:对于您的用例,如果您将“pack”替换为“args”,将“op”替换为“+",那么它将如下所示:
所有变体都有用例,但让我先向你展示基于一元右折叠的最简单的解决方案:
这真的非常简洁。
你可以在CPP参考中读到这里会发生什么。
解释fold表达式的示例化如下扩展表达式e:
1.一元右折叠(E运算...)变为(E1运算(...运算(EN-1运算EN)))
对于我们上面的折叠表达式
(args + ...)
,我们将得到如下:(1 + ( 2 + (3 + 4)))
。对于“+”运算符,我们可以省略所有大括号,最后得到:1 + 2 + 3 + 4
.尼斯
请参见下面的一段代码,其中我们使用了折叠表达式的所有4个变体:
。
接下来,到第二部分,如何在参数包的每个参数上应用函数,也有很多可能的解决方案,但是,因为我在解释折叠表达式,我将展示一个小函数的解决方案,特别是lambdas,通过使用折叠表达式。
这里的解决方案的主要部分是结合使用'逗号'运算符和一元右折叠。
由于逗号运算符不常用,我们在这里再读一遍。
因此,
lhs, rhs
执行以下操作:首先,计算左操作数lhs并丢弃其结果值。然后,出现一个序列点,以便完成lhs的所有副作用。然后,计算右操作数rhs并由逗号运算符将其结果作为非左值返回。
这可以和一元右折完美结合。
让我们以lambda的最简单形式为例:
[]{}
。你只看到了捕获和主体。这是一个完全有效的Lambda。如果你想调用这个lambda,那么你可以简单地写[]{} ()
。这调用了一个空的lambda,什么也不做。只是为了演示的目的:如果我们使用求和示例:则将发生以下情况:
sum
()
调用函数,这是逗号运算符的“lhs如果你一步一步地分析一下,你就会明白了。
下一步就很简单了,你可以在你的lambda中填充更多的功能,这样,你就可以在一个参数包的所有参数上应用一个函数。
以下是您预期功能的示例:
当然,您可以消除lambda中所有不必要的换行符,使其更紧凑。
wbrvyc0a3#
如前所述,有很多方法可以做到这一点。也许最简单的解决方案是添加一个重载函数,该函数将处理3个或更多参数,并递归地调用自身,如下所示:
所以,我只添加了一行函数,这很容易理解和解释它是如何工作的,一般来说,通过将可变参数模板与递归结合起来,你可以使很多复杂的东西变得容易得多