【问题标题】:Why VS and gcc call different conversion operators here (const vs non-const)?为什么 VS 和 gcc 在这里调用不同的转换运算符(const vs non-const)?
【发布时间】:2019-09-03 05:52:45
【问题描述】:

这段代码当然是愚蠢的,但我只是为了说明问题而写的。 这里是:

#include <iostream>
using namespace std;

struct foo {
    int a = 42;

    template <typename T>
    operator T* () {
        cout << "operator T*()\n";
        return reinterpret_cast<T*>(&a);
    }

    template <typename T>
    operator const T* () const {
        cout << "operator const T*() const\n";
        return reinterpret_cast<const T*>(&a);
    }

    template <typename T>
    T get() {
        cout << "T get()\n";
        return this->operator T();
    }
};

int main() {
    foo myFoo;
    cout << *myFoo.get<const int*>() << '\n';
}

使用 Visual Studio 2019(ISO C++17,/Ox)编译时的输出为:

T get()
operator const T*() const
42

gcc 8.3 (-std=c++17, -O3) 的输出是:

T get()
operator T*()
42

所以我想知道为什么这两个编译器选择在给定这段代码的情况下调用不同的 const 限定转换?

如果我将get() 更改为get() const,则两者都调用const 版本的转换。但是 VS 通过从未标记为 const 的方法调用 const 转换不是违反标准吗?

编辑:

为了消除对reinterpret_casthere's a version without it 的一些混淆,它们仍然在两个编译器上产生相同的输出。

【问题讨论】:

  • 因为其中一个是错误的。 myFoo.get 不是const,所以我希望调用非const 转换版本。
  • @Someprogrammerdude foo::get&lt;int const*&gt; 致电 foo::operator&lt;int const&gt;。返回值确实是const int*
  • 您的代码似乎说明的问题比问题的实际内容要多得多。例如,您真的需要 reinterpret_casts 来重现输出吗?
  • @user463035818 不这么认为,我通常只是用reinterpret_cast 编写指针转换,因为它只是获取地址并将其视为指向另一种类型的指针,而static_cast 可以改变行为(但在这种情况下不是),而且 C 风格的指针转换很丑 :)
  • 呃...reinterpret_cast 和 c 风格的演员表一样丑陋。 Afaik 他们之间没有任何区别

标签: c++ operator-overloading constants operator-keyword


【解决方案1】:

方法:

template <typename T> foo::T get();

不是const

这意味着对象this 在其主体内部是一个指向foo 类型的指针(而不是const foo)。

因此,声明

this->operator T();

将调用 no-const 版本,因为 overload resolution

正如[over.match.best] 上的标准规定,no-const 版本是首选,因为它不需要任何演员表。 实际上,为了调用 const 版本,编译器应该隐式转换为 const 对象(即 const_cast&lt;const foo*&gt;(this))。


gccclang 都遵循我刚才所说的内容。

MSVC 根本不遵循这里的标准。

【讨论】:

  • 是的,我很清楚。我不明白的是为什么 Visual Studio 仍然选择调用const 版本,这违反了您描述的规则。
  • @adam10603 MSVC 不符合标准。
  • 是的,这也是我开始怀疑的,这不会让我感到惊讶。我会等一下,如果没有其他问题我会接受这个
  • 'foo' 中没有定义方法或成员函数或转换运算符。定义的是模板。所以问题是,应该实例化哪个模板。
  • @BiagioFesta 我不同意,这在旧的 VC++ 中是正确的,新的 VC++ 是标准的,但这并不意味着它没有错误。这应该报告给 MS,然后由 MS 修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 1970-01-01
  • 2016-07-24
  • 2021-10-31
  • 2018-12-02
相关资源
最近更新 更多