首页 > 解决方案 > 为什么 VS 和 gcc 在这里调用不同的转换运算符(const vs non-const)?

问题描述

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

#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_cast这里有一个没有它的版本,它仍然在两个编译器上产生相同的输出。

标签: c++operator-overloadingconstantsoperator-keyword

解决方案


方法:

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

不是。_ const

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

因此,声明

this->operator T();

const由于重载决议,将调用 no-版本。

正如标准所述[over.match.best],该版本no-const是首选,因为不需要任何演员表。实际上,为了调用const版本,编译器应该隐式转换为一个 const 对象(即const_cast<const foo*>(this))。


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

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


推荐阅读