【问题标题】:Lambda expression in C++17: trailing return type vs static_cast for type conversionC++17 中的 Lambda 表达式:用于类型转换的尾随返回类型与 static_cast
【发布时间】:2020-01-10 02:36:10
【问题描述】:

如何将int 转换为long 内/外的lambda 表达式正确?如何正确检查 lambda 中的数学溢出?

int n = 12; // input parameter from std::cin
int a = 23; // input parameter from std::cin
int i = 34; // input parameter from std::cin
auto f = [n, a] (int i) { return a * (n - (i - 1)); };
auto result = f(i);

在 lambda 内部/外部乘以整数后检查溢出的最佳方法是什么?

auto result = f(i);
if ((result > std::numeric_limits<int>::max()) || (result < std::numeric_limits<int>::min())) {
    cout << "overflow was detected" << endl;
}

我是否需要将 TRT(尾随返回类型)-&gt; long 添加到 lambda 以便从 int 正确转换为 long

auto f = [n, a] (int i) -> long { return a * (n - (i - 1)); };

我是否需要将 static_cast 添加到 lambda 才能从 int 正确转换为 long

auto f = [n, a] (int i) { return static_cast<long>(a) * (n - (i - 1)); };

或者,可能是,我需要结合这个?

auto f = [n, a] (int i) -> long { return static_cast<long>(a) * (n - (i - 1)); };

或者,可能,我需要写 lambda 的类型?

std::function< long( int ) > f = [n, a] (int i) { return a * (n - (i - 1)); };

【问题讨论】:

  • 为什么在这些问题中涉及 lambda 很重要? Lambdas 并不特别。它们只是代码。
  • @NicolBolas:如果 lambda 参数是 auto,这将很重要,因为这样选择合适的类型来保存乘法比如果不是。
  • @G.Sliepen:即使他们确实使用了auto,这与无约束的模板参数到常规函数没有什么不同。因此,即便如此,作为一个 lambda 表达式也与如何检测/防止数学运算中的整数溢出问题真正相关

标签: c++ lambda c++17 static-cast trailing-return-type


【解决方案1】:

您问题的第一部分是duplicate(尽管 C 问题,C++ 没有区别,并且包含 C++ 的重复项)。最重要的一点:您无法检测到有符号整数溢出 after 乘法,因为它已经导致了未定义的行为——除非您在下一个更大的数据类型中进行计算;但请注意,许多(但不是全部!)平台(包括现代 PC 硬件上的 Windows)上的 intlong 具有相同的大小,因此切换到 long 并不能保证避免溢出!如果您想安全,请使用来自&lt;cstdint&gt; 标头的数据类型(例如int16_tint32_tint64_t)。如果您有特定的理由坚持使用 int,则必须投入一些额外的工作才能保证下一个更大的类型。不过,这个问题并非特定于 lambda,而是涉及任何乘法(甚至加法)。

为了保证特定的返回类型(同样,问题不是特定于 lambda,而是任何类型的自动推导,无论是返回类型还是自动变量),这两种方法都很有价值(显式的尾随返回类型和强制转换),但是,如前所述,结果确实不同!

仅仅应用尾随返回类型就相当于拥有

[n, a] (int i) { return static_cast<long>(a * (n - (i - 1))); };
//                                         ^               ^

请注意,演员表放置在整个计算周围,即。 e.演员表在计算之后完成,这仍然在int 中完成。如果 int 和 long do 的大小不同,则结果可能与您自己的转换变体不同:

[n, a] (int i) { return static_cast<long>(a) * (n - (i - 1)); };

因为这已经强制执行在 long 中进行的乘法(但不是减法!– 要强制执行这些,您也需要强制转换 i)。这种强制转换完全足以获得所需的返回类型;但是,显式尾随返回类型(另外)更清楚地显示了 lambda 实际返回的内容,而无需查看实现。如果您有一个更复杂的 lambda,这尤其有用,并且如果您有多个退出点,它可以帮助保证一致的返回类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 2017-03-16
    • 1970-01-01
    • 2023-03-12
    • 2018-10-09
    • 2015-06-07
    • 2021-01-18
    相关资源
    最近更新 更多