我有一个名为array
的简单数据结构(类似于std :: array)。 array
类有一个名为all()
的方法。这是方法声明:
const range<const_type_pointer> all() const;
range<type_point> all();
range
是类模板,由两个迭代器构成。以下是range
类声明的简化版本:
template <typename Iterator>
class range {
typedef typename iterator_traits<Iterator>::type_value type_value;
typedef typename iterator_traits<Iterator>::type_reference type_reference;
typedef typename iterator_traits<Iterator>::type_pointer;
range(Iterator begin, Iterator end);
// methods & algorithms
// data members
mutable Iterator _begin;
mutable Iterator _end;
};
所以基本上,如果我在const array
对象上调用all,它应该调用const
方法的重载并返回const range
。现在,在我的算法部分,我有简单的算法和以下签名:
template <typename UnaryFunction>
range forEach(UnaryFunction function);
然后我尝试了以下测试:
void test1(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int i) { std::cout << i << " "; });
}
第二个:
void test2(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int& i) { ++i; });
}
在第一种情况下,我只是打印变量i
,编译器没有抱怨,即使我在const range
对象上调用了非const range
方法。在第二种情况下,编译器抱怨。这种行为是标准的吗?
作为编译器,我使用的是MSVS编译器。
答案 0 :(得分:1)
auto
就像模板参数推导一样,这意味着它会删除顶级引用和顶级const
&amp; volatile
限定符。换句话说,在这两种情况下,r
的类型都为range<const_pointer_type>
。
当您了解其行为的所有详细信息并且确实知道您想要它们时,只应在非常特殊情况下返回const
限定对象
通常,您应该只返回没有cv-qualifiers的对象。移动语义会更好,并且不会导致不正确的期望。
答案 1 :(得分:1)
首先。如果您要返回const range
或range
,那么您将按价值返回,这并没有什么区别。
二。 auto r = array.all();
创建all
返回的任何内容的副本。您的r是非const对象,并且使用非const forEach
。但由于迭代器在第二个版本中是const,因此无法修改迭代。