为什么VS和gcc在这里调用不同的转换运算符(常量与非常量)?

时间:2019-04-12 12:52:59

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

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

#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的困惑,它们仍然在两个编译器上产生相同的输出。

1 个答案:

答案 0 :(得分:1)

方法:

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

不是 const

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

因此,声明

this->operator T();

由于overload resolution而将其称为no-const版本。

根据[over.match.best]的标准规定,首选版本no-const,因为它不需要任何 cast 。 确实,为了调用const版本,编译器应隐式转换为const对象(即const_cast<const foo*>(this))。


gccclang都遵循我刚才所说的话。

MSVC根本不遵循此处的标准。