首先,非常明确,std::vector<const Obj*> 和std::vector<Obj*>是两个不同类型,而且没有隐式的cast。更进一步,即使你愿意自己写代码cast,严格来说,考虑到可能存在特化,它们之间还不存在一定安全的复杂度为O(1)的cast(非O(1)的我想你也不乐意用)。
所以,需要考虑的是为什么要把std::vector<Obj*>当作std::vector<const Obj*>类型的参数?如果你仅仅是觉得func里面的实际操作,只需要const Obj*,那你应该单独为这部分操作独立定义一个函数:
void func_impl(const Obj*);
然后在各自的调用地方执行vector相关的操作。
如果你觉得外部的vector相关的操作也很通用,那么可以加一个模板形式的wrapper:
template <typename T> void func(const std::vector<T*>&);
然后通过这个func再调用上面的那个func_impl。
当然,如果以后不局限于vector,把这个wrapper写得更通用一点也是可以的:
template<typename T> void func(const T&);
总之,代码结构设计并不是一个简单的const或者随手写一个func就完事的了,这是一个配套项目。你现在捶胸顿足,说明你已经认识到了你之前的代码结构设计不合理,但你的怨气都指向了const,说明你还没有真正意识到是哪里的设计不合理。
问题不在const上,但这个的确算是C++设计时的瑕疵,但又不能说是bug……
而且我觉得也不好认为这是泛型协变/逆变的问题。
A<T*>
和A<const T*>
一定有同样的实现吗?
不尽然,因为模板类可以特化,两者完全可以有截然不同的内存布局、成员函数,甚至功能……
所以从语法角度,不接受vector<Obj*>
是合理的,除非你给出了operator vector<const Obj*>()
。
与之相似的情况还有,就算你的vector存的是const Obj*
,如果你用了其他的allocator,也一样不被接受,因为Allocator也在模板参数列表里……
但显然,对于用户来说,vector本身已经是const,allocator是什么又有什么关系呢?
不过对于这一问题,C++17靠pmr::vector
来“规避”了——allocator都被固定成同一种了,具体类型成了擦除类型的成员变量。
回到你遇到的const问题。哪怕vector<const T*>
和vector<T*>
之间不能互相转换吧,但本来你需要的只是“const的一堆连续的const T*”,而vector并不是必要条件。所以在C++20语境下会自然而然地联想到用std::span
。
然而span<const T*>
并不能隐式通过vector<T*>
来构造。
不过幸好,你还能手动构造,虽然要显式做const_cast:{const_cast<const T**>(v.data), v.size()}
。非常不美观,但至少不需要reinterpret_cast那样的风险……
补充:应该用span<const T* const>
,就能隐式构造了。
看来这部分隐式转换的知识我还是不够懂……
只能说,多用const是一个好习惯,但C++的设计使得有时候它反而会成为阻碍……
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有