参数包提取

Parameter pack extraction

我有一个 function2,可以使用或不使用第二个参数 == char 来调用它。 如果是这样,我想修改那个字符参数。

给出

void function1_caller(int x) { 
    char ws=7; 
    function2_modifyArg(x, ws); 
}

这个有效:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, ws ...);
}

简单地放在括号中,已经不起作用:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, (ws ... )); 
}

这会导致以下错误:

Syntax error: unexpected token '...', expected declaration

其实这里我想修改一下论点,当然 我也一样

Syntax error: unexpected token '...', expected declaration
template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, (ws ... / 3));
}

template <typename ... WS> 
void function3_end(int x, WS ... ws) {};

ws... 扩展为 ws 中值的 comma-separated 列表,但仅在特定上下文中,而不是此类列表可以产生有效语法的任何地方。其中一个上下文是 function3_end(x, ws ...).

中的一系列函数参数

(ws...)(ws... / 3) 都不允许。如果这只是给编译器的一条注释“嘿,将其展开然后尝试编译它”,两者实际上都会针对 non-empty 包进行编译,但第一个将是一系列逗号运算符,第二个将是将最后一个值除以 3。两者都没有编译器错误那么有用。第一个甚至可以使用折叠表达式显式完成,例如 (..., ws).

您可以做的是选择其中一个有效上下文并将模式应用于包中的每个元素:

function3_end(x, (ws/3)...);

这会在扩展的同时复制模式,并且在您看到一些示例后会非常直观地工作。省略号适用于其左侧的语法“组”,在本例中为 (ws/3),导致 (ws₀/3), (ws₁/3), (ws₂/3), … 的扩展。在 single-element 的情况下,这相当于 (ws₀/3),并且没有元素,整个模式被“复制”0 次,这正是您想要的。对于这个简单的模式,括号不是强制性的,但我通常会推荐它们以使扩展范围非常清晰。


综上所述,我宁愿避免使用模板并使用重载:

void function3_end(int x);
void function3_end(int x, char ws);

检测很简单——一个 body 用于第二个参数,一个用于没有。这也表明第二个参数是 char,而不是任何可能会或可能不会在顶部添加一些额外约束以使其伪装成 char 的类型。可变参数模板甚至没有表示不能使用超过 2 个参数调用此函数。此外,这些重载可以从它们的声明中分离出来并放入单独编译的源文件中,同时防止额外的模板实例化。最后,如果这会违反 DRY,您可以将公共部分分解为在两个重载中使用的单独函数。

你不需要括号你只需要把你想做的操作放在包扩展之前:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, ws / 3 ...);
}