为什么static_cast不使用转换运算符来指向const?

时间:2019-01-10 13:51:50

标签: c++ visual-studio-2012 casting implicit-conversion

在包装类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不使用const转换运算符?

或更具体地说,因为

Derived const *pd = static_cast<Derived const *>(static_cast<Base const *>(p));

有效:

为什么static_cast隐式转换为Base *,而不能Base const *隐式转换为staticCast()


The standard says

  

如果存在从表达式到new_type的隐式转换序列,或者用于直接初始化对象或表达式的new_type类型引用的重载解析将找到至少一个可行的函数,则static_cast(expression)返回虚数变量Temp好像是由new_type Temp(expression);初始化的,可能涉及隐式转换,对new_type的构造函数的调用或对用户定义的转换运算符的调用

[我的重点]


解决方法

由于这似乎是VisualStudio的错误,因此我将通过模板化的成员函数Derived const *pd = p.staticCast<Derived const *>(); (请参见上面的示例代码)来使用替代方法,如下所示:

U const *

要只允许强制转换为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(); } ,请使用SFINAE:

/* Override sorting header --> DataTable Bug */
.dataTables_scrollBody > table > thead > tr {
    visibility: collapse;
    height: 0px !important;
}

2 个答案:

答案 0 :(得分:4)

仅允许一次转换,因此您可以转换为@TestExecutionListeners(...),但此后不能转换为Get-ChildItem *.csv|select -First 1|Get-Content|select -First 1|Out-File -FilePath .\input.csv -Force #Get the header from one of the CSV Files, write it to input.csv Get-ChildItem *.csv|foreach {Get-Content $_|select -Skip 1|Out-File -FilePath .\Input.csv -Append} #Get the content of each file, excluding the first line and append it to input.csv

因此,您必须使用两个连续的强制转换。无论如何,它是更安全的,因为您声明知道自己正在从Base转换为Derived。永远不要从基类到派生类进行隐式转换。

答案 1 :(得分:3)

在尝试转换Pointer<Base>* ---(1)---> Base const* ---(2)---> {{1 }},其中:

  1. Derived const*
  2. 垂头丧气。

例如

Pointer<Base>::operator Base const*

Live demo