如何正确地声明从非常量迭代器到指针的常量指针
How to properly declare a const pointer from non-const iterator to pointer
背景
我正在实现一个模板过滤迭代器。给定任何类型的开始和结束迭代器,该迭代器将在范围内迭代,并跳过一元谓词返回false的任何元素。当然,我希望这个一元谓词总是有一个常量参数,以避免谓词修改支持容器。
支持迭代器可以是任何类型和容器的迭代器。它可以是基本类型、指针、引用、类。真的什么都可以。
我遇到了一个问题,我无法声明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
ness按比例向下指针。
这是一个模板元编程,它应该接受任何非const
指针并使其成为const
,以及其他一切都尽可能成为const
。它递归地操作,处理引用(r和l值)和对指针的引用到指针到指针的指针到指针,无论是否使用const
或volatile
修饰符,几乎在任何地方。
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>{};
实例
这是大量的措辞。它之所以如此详细,是因为没有简单的方法来匹配"类型修饰符"(指针、常量、volatile、引用等),所以最终必须非常具体和详细。
但它为您在使用时提供了一种干净的方法:
typedef std::vector<int*> vec_type;
typedef std::function<void(make_very_const_t<vec_type::iterator::value_type&>)> func_type;
它以一种应该隐式转换为.的方式在所有事物上喷出CCD_ 11
现在,即使这样也不能完全有效。std::vector< std::vector<int*> >
不会保护指向内部的int
不被修改。以上依赖于隐式转换为更const
的情况的能力——因此,为了实现这一点,我们必须在一个几乎任意的容器周围编写一个const强制包装器,该容器强制元素访问以完成上述转换。这很难。
通常,如果您想要一个int*
,其中作为const
的对象成为指向对象const
,则需要一个强制执行该要求的智能指针。N4388建议在标准中添加一个这样做的包装器,如果不是完全为了这个目的的话。
您的容器存储int*
s。您的函数接受"对int*
的常量引用"。这意味着指针指向可变数据。数据可以被愉快地修改,因为你允许它。注意"constness的程度"之间的区别-你不能改变指针指向什么,但你可以修改它们指向的int
s。因此,要解决这个问题,你的函数必须接受"const-reference toconst int*
"或const int*
。
typedef std::function<void(const int*)> func_type;
或者,如果你想让它更通用一点(参见Yakk的答案,了解更通用的解决方案):
#include <type_traits>
typedef std::vector<int*> vec_type;
typedef
std::add_pointer<
std::add_const<
std::remove_pointer<
vec_type::iterator::value_type
>::type
>::type
>::type value_t;
typedef std::function<void(const value_t&)> func_type;
- 将常量指针引用绑定到非常量指针
- 如何使用数据对象上的常量指针初始化类
- 为什么我收到"从常量指针到指针的转换无效?
- C++/QT:使用指向私有成员的常量指针作为只读数据共享
- 是否可以使用非常量指针调用非常量函数,以及当两个unique_ptrs指向同一个对象时程序的行为方式?
- 为什么C++中没有常量引用,就像常量指针一样?
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 将常量指针强制转换为非常量
- 带有常量指针的矢量构造函数示例
- 什么是常量指针常量引用类型的参数?(const X* const & p)
- 在多线程函数中返回共享的常量指针会导致计时问题吗?
- 常量指针上的混乱
- 使用 static_cast 时指向常量指针的原因
- 如何在C++中定义常量指针数组?
- 测试此指针的常量指针性质
- 当常量指针用作函数的参数时
- C++ - 无法将顶部常量指针分配给另一个非常量指针
- 在不同类型之间转换常量指针
- 解构常量指针?
- 为什么 std::vector<>::const_reference 可以转换为非常量指针?