为什么static_cast不使用转换运算符来指针指向const
Why does static_cast not use the conversion operator to pointer to const?
从我的包装类Pointer<Base>
,我只想返回指向const:Base const *
的指针
将Pointer<Base>
强制转换为Derived const *
时,我得到一个编译错误:
错误C2440:"static_cast":"Pointer"无法转换为"const Derived*">
(翻译自德语VS2012)
struct Base { };
struct Derived : public Base { };
template <typename T>
class Pointer {
public:
Pointer(T *t = nullptr) : p(t) { }
//operator T*() { return p; }
operator T const *() const { return p; }
template <typename U>
inline U staticCast() const { return static_cast<U>(d); }
private:
T *p;
};
int main(int argc, char *argv[]) {
Derived d;
Pointer<Base> p(&d);
Derived const *pd = static_cast<Derived const *>(p);
}
如果我启用转换operator T*() { return p; }
,它就会工作。
为什么static_cast
不使用常量转换运算符?
或者更具体地说,由于
Derived const *pd = static_cast<Derived const *>(static_cast<Base const *>(p));
作品:
为什么static_cast
可以隐式转换为Base *
,而不能转换为Base const *
,即使后者对于转换目标类型来说已经足够了?
标准规定:
如果存在从表达式到new_type的隐式转换序列,或者如果用于直接初始化对象的重载解析或来自表达式的new_type类型的引用将找到至少一个可行的函数,则static_cast(expression)返回虚变量Temp,该虚变量被初始化为new_type Temp(expression);,这可能涉及隐式转换、对new_type的构造函数的调用或对用户定义的转换运算符的调用。
[我强调]
解决方案
由于这看起来像是一个VisualStudio错误,我将通过模板化成员函数staticCast()
(请参阅上面的示例代码)来使用一个变通方法,如下所示:
Derived const *pd = p.staticCast<Derived const *>();
要只允许转换为U const *
,请使用SFINAE:
template <typename U>
struct is_pointer_to_const
{
static const bool value = std::is_pointer<U>::value
&& std::is_const<typename std::remove_pointer<U>::type >::value;
};
template <typename U>
inline U staticCast(typename std::enable_if<is_pointer_to_const<U>::value >::type* = 0) const
{ return static_cast<U>(d); }
template <typename U>
inline U staticCast(typename std::enable_if<!is_pointer_to_const<U>::value >::type* = 0) const
{ static_assert(false, "Type is not a pointer to const"); return U(); }
只允许一次转换,因此可以转换为Base
,但之后无法转换为Derived
。
所以你必须使用两个连续的强制转换。无论如何,它更安全,因为您声明您知道您正在从Base
转换为Derived
。您永远不应该有从基类到派生类的隐式转换。
当您尝试转换Pointer<Base>*
-(1)--->Base const*
-(2)--->Derived const*
时,需要分两个步骤进行处理,使用:
Pointer<Base>::operator Base const*
- 下行
例如
Base const* pb = static_cast<Base const *>(p);
Derived const *pd = static_cast<Derived const*>(pb);
现场演示。
- C++ 带有函数指针的运算符优先级
- 是否允许编译器省略对指针的 &* 运算符的组合调用?
- 错误:表达式必须具有算术、无作用域枚举或带有运算符重载的指针类型
- 重载 ostream << 运算符,指针作为参数,导致输出上的内存地址
- 在一个指令中声明更多指针的运算符优先级
- 为什么在通过引用返回运算符分配时取消引用'this'指针?
- SFINAE - 检测类型 T 是指针、数组还是带有随机访问运算符的容器,以及给定的值类型
- c++:复制、删除和运算符=在原始指针映射中
- 除了调用全局删除运算符之外,删除一个void指针还能做什么呢
- 类重载运算符 '<' 插入指向该对象集的共享指针时不调用
- 使用继承的指针列表复制构造函数或重载运算符=
- delete运算符如何处理c中的指针
- 为指针重载运算符++
- 在分配指向数组内存地址的指针时,为什么不必使用地址运算符?
- 如何从模板类重载创建的指针对象上的运算符?
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 为什么运算符"new"需要指针才能工作?
- C++运算符指针,乘法
- 运算符指针数组的新语法
- 重载运算符(指针)