for_each_arg`的正确用法-转发过多?

问题描述 投票:3回答:3

我很高兴发现for_each_arg(...),这使处理参数包变得更加容易。

for_each_arg(...)

但是,我对其正确用法感到困惑。有很多参数需要完美地转发,但是我是否执行了不必要的转发?

由于过度追求而难以阅读代码。

template<class F, class...Ts>
F for_each_arg(F f, Ts&&...a) {
 return (void)initializer_list<int>{(ref(f)((Ts&&)a),0)...}, f;
}

我所有的问题/疑问都在上述代码示例的注释中表达。

c++ lambda parameter-passing c++14 perfect-forwarding
3个回答
3
投票

您的代码中的每个struct UselessContainer { // Expects a perfectly-forwarded item to emplace template<typename T> void add(T&&) { } }; // Creates an `UselessContainer` already filled with `mArgs...` auto makeUselessContainer(TArgs&&... mArgs) { using namespace std; UselessContainer result; for_each_arg ( [&result, &mArgs...] // Am I capturing the `mArgs...` pack correctly here? (auto&& mX) // Am I passing the arguments to the lambda correctly here? { // Is this `forward` necessary? result.add(forward<decltype(mX)>(mX)); // Could it be replaced with // `result.add(forward(mX));` // ? }, forward<TArgs>(mArgs)... // I assume this `forward` is necessary. ); return result; } 实际上都是将所有参数完美转发到最后的必要条件。右值引用的名称是左值,因此除非每次传递参数时都转发,否则值类别信息将丢失。同样,如果没有显式模板参数列表,则无法调用forward,因为模板参数仅在一个非推导上下文中使用。实际上,在没有显式参数列表的情况下调用的函数模板无法完成此工作。

您可以尝试使用宏来稍微缩短代码:

forward

然后变成

#define FORWARD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)

首先也可以使用宏代替for_each_arg ( // Removed superfluous capture [&result] (auto&& mX) { result.add(FORWARD(mX)); }, FORWARD(mArgs)... );

for_each_arg

1
投票
#define FOR_EACH_ARG(...) (void)std::initializer_list<int>{((__VA_ARGS__),0)...}

FOR_EACH_ARG( result.add(forward<TArgs>(mArgs)) );

仅在制作这种Lambda时捕获for_each_arg ( [&](auto&& mX){ result.add(std::forward<decltype(mX)>(mX)); }, std::forward<TArgs>(mArgs)... ); 。如果必须列出,则仅需要捕获&

[&result始终与类型参数一起使用。

注意Eric的for_each_arg是不完善的,并且大多数情况下是用140个字符或更少的字符来完成的。 ;)它的缺点是轻微的,在这里无害。

这里是替代方法:

首先,写这个:

forward<?>

它需要零个arg lambda,并从左到右运行它们。

然后将对template<class...Fs> void do_in_order(Fs&&...fs){ int _[]={0, (((void)(std::forward<Fs>(fs)())),0)... }; (void)_; // kills warnings } 的呼叫替换为:

for_each_arg

缺点是更多的编译器不喜欢上面的。

do_in_order( [&]{ result.add(std::forward<TArgs>(mArgs)); }... ); 中表达式的顺序由n4296 8.5.4 / 4 8.5.4 / 1 8.5 / 15 8.5 / 1中的[dcl.init]和[dcl.init.list]节保证。初始化是一个复制列表初始化(8.5 / 15和8.5.4 / 1),是一个bracket-init-list的“ initializer-list”(8.5 / 1),并且这样的顺序是从左到右(8.5.4 / 4)。


0
投票

我的建议:

do_in_order

[还有选择如何将笛卡尔积线性化/序列化为元组序列(“ writeme”部分)。

© www.soinside.com 2019 - 2024. All rights reserved.