65.9K
CodeProject 正在变化。 阅读更多。
Home

深入探索 – Fold 表达式

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2023年5月22日

CPOL

2分钟阅读

viewsIcon

6140

极端情况下的 Fold 表达式

自 C++17 以来,折叠表达式就已存在,并且对我们处理可变模板的方式产生了重大影响。 很久以前,我写过关于 折叠表达式 作为元编程系列的一部分,但今天,我们将探索折叠表达式用法的极端情况。

在开始之前,一个重要的免责声明:在本文中,代码示例展示了使用值传递参数的可变模板用法,而没有转发它们。这样做是为了简化它们,并专注于示例背后的思想。

空的可变参数

在单折叠(没有初始化的折叠表达式)的情况下,此情况对于 3 种类型的运算符是合法的:&&||,

运算符 &&

template <typename ...Args>
auto and_cond(Args... args) {
    return (args && ...);
}

在参数为空的情况下(对于调用 and_cond()),函数将返回 true。对这个决定的一个合理的解释可能是 && 运算符要求不会有任何部分评估为 false。在这种情况下,根本没有任何部分,因此没有任何部分评估为 false,因此结果应该是 true

运算符 ||

template <typename ...Args>
auto or_cond(Args... args) {
    return (args || ...);
}

在参数为空的情况下,函数将返回 false。对这个决定的一个合理的解释可能是 || 运算符要求至少有一个部分将评估为 true。因为根本没有任何部分,所以没有任何部分评估为 true,因此结果是 false

运算符 ,

template <typename ...Args>
auto comma_op(Args... args) {
    return (args , ...);
}

在这种情况下,当没有传递参数时,结果将是 void()

其他运算符

对于其他运算符,任何不带参数的调用都不会编译。

带单个参数的可变包

在这里,事情变得有点出乎意料。当只传递一个参数给可变包时,结果将忽略运算符并返回与发送给函数的类型和参数相同的类型(在 gcc 13.1.0 和 clang 16.0.0 上进行了测试)。例如

template <typename ...Args>
auto func(Args ...args)
{
    return (args || ...);
}

int main() {
    using namespace std::string_literals;
    std::cout << func("I am a string"s); // Will print "I am a string"
    return EXIT_SUCCESS;
}

根据 C++ Insights 生成的代码是

template<>
std::basic_string<char> func<std::basic_string<char>>(std::basic_string<char> __args0)
{
  return std::basic_string<char>(static_cast<std::basic_string<char>&&>(__args0));
}

对于任何其他运算符,包括 +=.*->,也会是相同的。

无参数的二元折叠表达式

与具有单个参数的单折叠表达式应用相同的规则,也适用于无参数的二元折叠表达式

template <typename ...Args>
auto func(Args ...args)
{
    return (args ->* ... ->* "I am a string"s);
}

int main() {
    std::cout << func(); // Will print "I am a string"
    return EXIT_SUCCESS;
}

C++ Insights 生成的代码

template<>
std::basic_string<char> func<>()
{
  return std::operator""s("I am a string", 13UL);
}

结论

我们必须密切关注极端情况,并且永远不能指望基本逻辑站在我们这边(谁会相信我们可以将一个 std::string 发送到使用 ||&& 运算符的折叠表达式中?)。

本文的灵感来自于 Daisy Hollman 和我之间的一次对话。 谢谢 Daisy! ❤

一个不相关的注释:我的文章发布频率在过去几个月里有所下降。原因是为在 Core C++ 中的 Core C++(猜猜哪次对话促成了这篇文章)上 Daisy 和我的演讲做准备。

© . All rights reserved.