3

C++11的auto类型很方便,所以现在也想要一个const_auto类型。例如,假设std::list<T> a;,如果

auto p = a.begin();

有类型std::list<T>::iterator,然后希望

const_auto p = a.begin();

有类型std::list<T>::const_iterator。不幸的是,C++11 似乎没有听说过const_auto. 因此,如何才能以良好的风格达到预期的效果?

(有关信息,请在此处询问和回答相关问题。

4

3 回答 3

13

C++11 确实允许您编写

const auto p = a.begin();

但是,这并不能满足您的要求。这使得常规迭代器对无法更改其值的非常量数据。

右边的a.begin()类型由 的类型决定a,而不是由左边的任何东西决定。如果 a 是非常量,a.begin()则将调用非常量版本的 。因此,您可以强制a转换为 const& 然后使用它,或者您可以对 a 进行常量引用并使用它:

const auto& b = a;
auto p = b.begin();

然而,更简单的方法是使用新引入的 .cbegin() 和 .cend():

auto p = a.cbegin();
于 2013-06-22T01:29:15.593 回答
3

我经常发现将实例转换为其类型的版本很有用const,但我发现 usingconst_cast为此目的很粗俗(保留它以删除 const,现在搜索它会发现危险代码),而且它过于冗长(重复完整类型?嘎!)

因此这个片段:

template<typename T>
T const& as_const( T& t ) { return t; }

然后您将使用它来解决您的问题,如下所示:

auto p = as_const(a).begin();

我相信这是非常自我记录的。

于 2013-06-24T18:57:12.377 回答
2

C++11 中有 STL 容器和 C 数组的函数模板。见std::begin()std::end()。不幸的是,没有等效的std::cbegin()std::cend()出于某种原因。

你可以使用这些函数来做你想做的事:

template<class T, size_t N>
T const * cbegin(T(&a)[N])
{
    return &a[0];
}

template<class T, size_t N>
T const * cend(T(&a)[N])
{
    return &a[N];
}

template<class T>
typename T::const_iterator cbegin(T const & container)
{
    return container.cbegin();
}

template<class T>
typename T::const_iterator cend(T const & container)
{
    return container.cend();
}

最后两个也可以声明为:

template<class T>
auto cbegin(T const & container) -> decltype(container.cbegin())
{
    return container.cbegin();
}

template<class T>
auto cend(T const & container) -> decltype(container.cend())
{
    return container.cend();
}

从那里你可以这样做:

char x[] = "ab";

auto b = cbegin(x);
auto e = cend(x);
于 2013-06-22T02:38:27.310 回答