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

fre*_*low 5 c++ lambda decltype template-meta-programming c++11

在算法中,我想创建一个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
    };
}
Run Code Online (Sandbox Code Playgroud)

编译器不喜欢这段代码:

错误:»const«-qualifier不能应用于»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)
Run Code Online (Sandbox Code Playgroud)

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

问题1:decltype(*it)&总是一样的decltype(*it)吗?

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

Ste*_*sop 4

问题 1:不,对 InputIterator 的要求仅仅是可*it转换为 T(“迭代器要求”中的表 72)。

decltype(*it)例如,const char&对于一个 为 的迭代器来说value_type也是如此int。或者也可能是int。或者double

usingiterator_traits不等于 using decltype,决定​​你想要哪个。

出于同样的原因,auto value = *it;不一定会您提供具有迭代器值类型的变量。

问题 2:可能取决于您所说的模板元编程的含义。

如果使用的特征类型是 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
    };
}
Run Code Online (Sandbox Code Playgroud)

您可能必须捕获ret_type才能使用其类型,我目前无法轻松检查。

不幸的是,它会额外取消引用迭代器。您可能可以编写一些聪明的代码来避免这种情况,但聪明的代码最终将成为 的替代版本remove_reference,即 TMP。