c++ - 如何正确声明从非常量迭代器到指针的常量指针

标签 c++ c++11 const-correctness

背景

我正在实现一个模板过滤迭代器。给定任何类型的开始和结束迭代器,此迭代器将迭代范围并跳过一元谓词返回 false 的任何元素。当然,我希望这个一元谓词始终有一个 const 参数,以避免谓词修改支持容器。

后备迭代器可以是任何类型和容器的迭代器。它可以是基本类型、指针、引用、类。真的什么都可以。

我遇到了一个问题,无法根据模板参数迭代器声明 std::function 来获得正确的 const 声明的参数。我提取了一个最小的代码示例来说明问题。

代码

#include <vector>
#include <functional>

typedef std::vector<int*> vec_type;
typedef std::function<void(const vec_type::iterator::value_type&)> func_type;

void foo(vec_type& a, func_type f){
  for (auto it = a.begin(); it != a.end(); ++it){
    f(*it);
  }
}

int main(int, char**){
  vec_type v;
  int a = 3;
  int b = 4;
  v.push_back(&a);
  v.push_back(&b);
  foo(v, [](int* x){*x = 0; });
  return 0;
}

我预计 lamda 会出现编译错误,因为 int* 应该是 const int* 但 GCC 4.8.1 和 VS2013 都允许它并愉快地修改我的内容思想是一个常量。

最佳答案

当您修改指针指向的内容时,指针容器不会被修改:容器拥有指针,而不是所指向的内容。

但我理解——有时你想要 const传播向下指针的能力。

这是一些模板元编程,应该采用任何非 const指针并使其const ,以及其他所有内容都变为 const尽其所能。它以递归方式操作,处理引用(r 和 l 值)以及对指针的指针的引用,对指针的指针的引用,无论有或没有 constvolatile修饰符几乎无处不在。

template<class T>struct tag{using type=T;};

template<class X>
struct make_very_const:tag<const X> {};
template<class X>
using make_very_const_t=typename make_very_const<X>::type;
// makes code below easier to write (namely, the pointer code):
template<class X>
struct make_very_const<const X>:tag<const make_very_const_t<X>> {};
template<class X>
struct make_very_const<volatile X>:tag<const volatile make_very_const_t<X>> {};
template<class X>
struct make_very_const<const volatile X>:tag<const volatile make_very_const_t<X>> {};
// references:
template<class X>
struct make_very_const<X&>:tag<make_very_const_t<X>&>{};
template<class X>
struct make_very_const<X&&>:tag<make_very_const_t<X>&&>{};
// pointers:
template<class X>
struct make_very_const<X*>:tag<make_very_const_t<X>*const>{};
// std::reference_wrapper:
template<class X>
struct make_very_const<std::reference_wrapper<X>>:tag<std::reference_wrapper<make_very_const_t<X>>const>{};

live example

这是很多废话。它如此冗长的原因是没有简单的方法来匹配“类型修饰符”(指针、常量、 volatile 、引用等),因此您最终必须非常具体和冗长。

但它为您提供了一种在使用时执行此操作的干净方法:

typedef std::vector<int*> vec_type;
typedef std::function<void(make_very_const_t<vec_type::iterator::value_type&>)> func_type;

喷出const以一种应该隐式转换的方式覆盖所有内容。

现在,即使这样也不是完全有效。一个std::vector< std::vector<int*> >不会保护指向内部int免遭修改。以上依赖于隐式转换为 more const 的能力因此,为了实现这一点,我们必须在几乎任意的容器周围编写一个常量强制包装器,强制元素访问经历上述转换。这很难。

一般来说,如果您想要 int*其中对象是 const使指向的对象const ,您需要一个智能指针来强制执行该要求。 N4388是添加一个包装器的提案,该包装器可以按照标准执行此操作(如果不完全用于此目的)。

关于c++ - 如何正确声明从非常量迭代器到指针的常量指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29539611/

相关文章:

c++ - ']' 标记之前的预期表达式? C

c++ - 分离线程的参数问题

c++ - 找到所有连接对的总和的高效算法

c++ - 在 vector 中存储模板化对象指针并通过基类指针访问

c++ - 从 nullptr_t 到 bool : valid or not? 的转换

C++ : automatic const?

c++ - const 函数重载

c++ - 如何正确地将 _bstr_t 重置为 `NULL`

c++ - 使用枚举与变量,存储非类型模板参数值。 (在 Int2Type<int v> 模板中)

C++11 std::function const 重载歧义