在算法中,我想创建一个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:如何在没有模板元编程的情况下通过引用传递元素?
答案 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。