通过对const的引用将元素传递给lambda

Passing an element to a lambda by reference-to-const

本文关键字:元素 lambda 引用 const      更新时间:2023-10-16

在一个算法中,我想创建一个lambda,它通过引用const来接受一个元素:

template<typename Iterator>
void solve_world_hunger(Iterator it)
{
    auto lambda = [](const decltype(*it)& x){
        auto y = x;   // this should work
        x = x;        // this should fail
    };
}

编译器不喜欢这段代码:

错误:»const«限定符不能应用于»int&«(从德语手动翻译)

然后我意识到decltype(*it)已经是一个参考,当然这些不能成为const。如果我删除const,代码可以编译,但我希望x = x失败。

让我们相信程序员(就是我)一分钟,摆脱const和显式&,无论如何,由于引用崩溃规则而被删除。但是等等,decltype(*it)实际上是保证是一个引用,还是我应该添加显式的&以确保安全?

如果我们不信任程序员,我可以想到两种解决问题的方法:

(const typename std::remove_reference<decltype(*it)>::type& x)
(const typename std::iterator_traits<Iterator>::value_type& x)

你可以自己决定哪一个更丑。理想情况下,我想要一个不涉及任何模板元编程的解决方案,因为我的目标受众以前从未听说过。所以:

问题1:decltype(*it)&是否总是与decltype(*it)相同?

问题2:如何在没有模板元编程的情况下通过引用到const传递元素?

问题1:不,InputIterator的要求仅仅是*it可以转换为T(参见"Iterator要求"中的表72)。

例如,对于value_typeint的迭代器,decltype(*it)可以是const char&。也可能是int。或double .

使用iterator_traits不等于使用decltype,决定你想要哪个。

出于同样的原因,auto value = *it;也没有给你一个迭代器值类型的变量。

问题2:可能取决于你所说的模板元编程是什么意思。

如果使用的trait类型是TMP,那么没有TMP就没有办法指定"指向迭代器值类型的const引用",因为iterator_traits是访问任意迭代器值类型的唯一方法。

如果你想要const-ify decltype,那么这个呢?

template<typename Iterator>
void solve_world_hunger(Iterator it)
{
    const auto ret_type = *it;
    auto lambda = [](decltype(ret_type)& x){
        auto y = x;   // this should work
        x = x;        // this should fail
    };
}

为了使用它的类型,你可能必须捕获ret_type,我现在不能轻易检查。

不幸的是,

会在额外的时间内解除对迭代器的引用。您可能可以编写一些聪明的代码来避免这种情况,但聪明的代码最终将成为remove_reference的替代版本,因此TMP。