首页 > 解决方案 > 不同版本的g++重载解析结果不一致

问题描述

当我使用 g++ 5.4.0 时,下面的示例代码按预期工作,但在我将 g++ 更新到 10.2.0 后,结果发生了变化。我还在clang++ 11.0.1上测试了示例代码,结果和g++ 5.4.0一样。

我搜索了一些相关问题,但没有得到有效的答案。据我所知,重载函数应该在模板之前匹配,为什么g++ 10.2.0会得到不同的结果,我该如何解决这个问题?

因为原来的源代码很复杂,用其他的c++特性来重构并不容易,这个问题能不能稍微改动一下就解决?

示例代码的目标是使用重载函数Base::operator const std::string&()执行一些特殊动作,使用模板函数执行常见动作。

#include <string>
#include <iostream>

class Base 
{
public:
    template <class T>
    operator const T&() const;
    virtual operator const std::string&() const;
};

template <class T>
Base::operator const T&() const
{
    std::cout << "use template method" << std::endl;
    static T tmp{};
    return tmp;
}

Base::operator const std::string&() const
{
    std::cout << "use overload method" << std::endl;
    const static std::string tmp;
    return tmp;
}

template <class T>
class Derive : public Base
{
public:
    operator const T&() const
    {
        const T& res = Base::operator const T&();
        return res;
    }
};

int main()
{
    Derive<std::string> a;
    const std::string& b = a;
    return 1;
}

g++ 5.4.0 结果:

g++ -std=c++11  main.cpp -o test && ./test
use overload method

g++ 10.2.0 结果:

g++ -std=c++11 main.cpp -o test && ./test          
use template method

clang++ 11.0.1 结果:

clang++ -std=c++11  main.cpp -o test && ./test
use overload method

标签: c++templatesg++language-lawyeroverload-resolution

解决方案


这绝对是一个 GCC 错误:

template <class T>
class Derive : public Base {
 public:
  operator const T&() const override {
    using Y = std::string;
    static_assert(std::is_same<T, Y>::value, "");
    
    std::string static res;

    res = Base::operator const Y&();
    res = Base::operator const T&();
    return res;
  }
};

在这里,虽然调用了两个不同版本的运算符,但Y它们T是相同的。Godbolt

Clang 具有正确的行为,您可以将其用作解决方法。请报告该错误,以便可以在 GCC 的后续版本中修复它。


推荐阅读