5

在算法内部,我想创建一个通过引用到常量接受元素的 lambda:

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&«(手动翻译自德语)

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

4

1 回答 1

4

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

decltype(*it)例如const char&,对于value_typeis的迭代器,可能是这样int。或者它可能是int。或double

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

同理,auto value = *it;不一定给你一个具有迭代器值类型的变量

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

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

如果你想 const-ifydecltype那么这个怎么样?

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才能使用它的类型,我目前无法轻松检查。

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

于 2013-01-18T12:20:50.337 回答