-1

如何正确转换intlonglambda 表达式的内部/外部?如何正确检查 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(尾随返回类型)添加-> long到 lambda 才能正确转换为intto long

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

我是否需要添加static_cast到 lambda 才能正确转换intlong

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)); };
4

1 回答 1

2

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

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

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

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

请注意,演员表是围绕整个计算进行的,即演员表是在计算之后完成的,这仍然是在int. 如果 int 和 long 的大小确实不同,则结果可能与您自己的转换变体不同:

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

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

于 2019-09-07T16:29:10.707 回答