我试图通过制作这个指针包装器(替换原始指针)来发布此代码作为这个问题的答案.这个想法是委托const
给它的指针,以便filter
函数不能修改值.
#include#include template class my_pointer { T *ptr_; public: my_pointer(T *ptr = nullptr) : ptr_(ptr) {} operator T* &() { return ptr_; } operator T const*() const { return ptr_; } }; std::vector > filter(std::vector > const& vec) { //*vec.front() = 5; // this is supposed to be an error by requirement return {}; } int main() { std::vector > vec = {new int(0)}; filter(vec); delete vec.front(); // ambiguity with g++ and clang++ }
Visual C++ 12和14编译时没有错误,但GCC和Coliru的Clang声称存在歧义.我期待他们选择非常量std::vector::front
超载然后my_pointer::operator T* &
,但没有.为什么?
[expr.delete]/1:
操作数应该是指向对象类型或类类型的指针.如果是类类型,则操作数在上下文中被隐式转换(Clause [conv])为指向对象类型的指针.
[转]/5,强调我的:
某些语言结构需要转换为具有适合于该构造的一组指定类型之一的值.出现在这样的上下文中
e
的类类型的表达式E
被称为上下文隐式转换为指定类型T
,并且当且仅当e可以隐式转换T
为如下确定的类型时才是格式良好的 :E
搜索非显式的转换函数,其返回类型cv T
或引用cv T
,使得T
由上下文允许的.应该只有一个这样的T
.
在你的代码中,有两个这样的T
s(int *
和const int *
).因此,在您进行超载分辨率之前,它是不正确的.
请注意,C++ 11和C++ 14之间的区域有所变化.C++ 11 [expr.delete]/1-2说
操作数应具有指向对象类型的指针,或具有指向对象类型的指针的单个非显式转换函数(12.3.2)的类类型.[...]
如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,[...]
如果按字面意思读取,将允许您的代码并始终调用operator const int*() const
,因为int* &
它是引用类型,而不是指向对象类型的指针.在实践中,实现将转换函数视为"引用指向对象的指针" operator int*&()
,然后拒绝代码,因为它具有多个合格的非显式转换函数.