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

时间:2013-01-18 12:01:54

标签: c++ c++11 template-meta-programming lambda decltype

在算法中,我想创建一个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«-qualifier不能应用于»int&amp;«(从德语手动翻译)

然后我意识到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:如何在没有模板元编程的情况下通过引用传递元素?

1 个答案:

答案 0 :(得分:4)

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

因此,对于decltype(*it)const char&的迭代器,value_type可以是int。或者它可能是int。或double

使用iterator_traits并不等同于使用decltype,决定您想要的是什么。

出于同样的原因,auto value = *it; not 不一定会给你一个带迭代器值类型的变量。

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

如果使用traits类型是TMP,那么没有TMP就无法指定“对迭代器的值类型的const引用”,因为iterator_traits是访问任意迭代器的值类型的唯一方法

如果你想要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。

相关问题