Lambda函数类型蠕变

时间:2016-09-09 18:49:48

标签: c++ lambda casting type-conversion

让我们看一下以下代码:

tbb::blocked_range<int> range(0, a.rows);
uint64_t positive = tbb::parallel_reduce(range, 0, // <- initial value
  [&](const tbb::blocked_range<int>& r, uint64_t v)->uint64_t {
    for (int y = r.begin(); y < r.end(); ++y) {
        auto rA = a[y], rB = b[y];
        for (int x = 0; x < a.cols; ++x) {
            auto A = rA[x], B = rB[x];
            for (int l = y; l < a.rows; ++l) {
                auto rAA = a[l], rBB = b[l];
                for (int m = x; m < a.cols; ++m) {
                    if (l == y && m == x)
                        continue;
                    auto AA = rAA[m], BB = rBB[m];
                    if ((A == AA) && (B == BB))
                        v++; // <- value is changed
                    if ((A != AA) && (B != BB))
                        v++; // <- value is changed
                }
            }
        }
    }
    return v;
}, [](uint64_t first, uint64_t second)->uint64_t {
    std::cerr << first << ' + ' << second;  // <- wrong values occur
    return first+second;
}
);

这是一个并行缩减操作,其中初始值为0.然后,在每个并行计算中,基于初始值,我们计算(第一个lambda函数中的局部变量v)。第二个lambda函数汇总了并行工作者的结果。

有趣的是,此代码按预期工作。第二个lambda函数的输出将显示由整数溢出产生的巨大数字。

使用以下代码替换第二行时,代码可以正常工作:

uint64_t positive = tbb::parallel_reduce(range, (uint64_t)0, // <- initial value

现在我想知道。不会对第一个lambda(uint64_t v)的定义执行此强制转换,以及应该在uint64_t上运行的函数如何在int上运行?

编译器是GCC 6。

1 个答案:

答案 0 :(得分:3)

lambda采用什么参数并不重要。根据{{​​3}},一切都基于第二个参数的类型:

template<typename Range, typename Value,
         typename Func, typename Reduction>
Value parallel_reduce( const Range& range, const Value& identity,
                       const Func& func, const Reduction& reduction,
                       [, partitioner[, task_group_context& group]] );

伪签名:

Value Func::operator()(const Range& range, const Value& x)
Value Reduction::operator()(const Value& x, const Value& y)

因此,Value会传递到Func并传递到Reduction并返回。如果您希望uint64_t无处不在,则需要确保Valueuint64_t。这就是为什么您的(uint64_t)0有效,但您的0没有(并且实际上是未定义的引导行为)。

请注意,这与普通the docs

相同
std::vector<uint64_t> vs{0x7fffffff, 0x7fffffff, 0x7fffffff};
uint64_t sum = std::accumulate(vs.begin(), vs.end(), 0, std::plus<uint64_t>{});
                                //                  ^^^ oops, int 0!
                                //           even though I'm using plus<uint64_t>!
assert(sum == 0x17ffffffd);     // fails because actually sum is truncated
                                // and is just 0x7ffffffd