C++模板类对于不同的编译器的行为不同

C++ template class behaves differently for different compilers

本文关键字:编译器 于不同 C++      更新时间:2023-10-16

我正在使用C++模板。使用 MSVC 编译器编译和使用 Mingw gcc 编译器时,使用模板和友元类有什么区别吗?我的代码在使用 MSVC 编译时成功编译并给出所需的输出,但在使用 gcc 编译时会出错。下面是我的代码,

///////////Record.h/////////////////////
#include "Base.h"
class Derived1;
class Derived2;
template <class TYPE_LIST> class List;
class FRecord
{
public:
    FRecord();
    virtual ~FRecord();
    friend class Base;
#if _MSC_VER <= 1200
    friend class List<Derived1>;
    friend class List<Derived2>;
#else
    template <class TYPE_LIST> friend class List;
#endif
};
///////////////////////////////////////////////////////////////
///////////////////Base.h/////////////////////////////////
class Base
{
public:
    Base(const HEADER *hc, const FRecord *fr);
    virtual ~Base();    
    __inline bool IsNonValid() const;
protected:
    quint32 Size;
};
/////////////////////////////////////
// Data
/////////////////////////////////////
template <class TYPE_LIST>
class Data : public TYPE_LIST
{
public:
    Data(const HEADER *hc, const FRecord *fr) : TYPE_LIST(hc, fr)
    {
        QString val = IsNonValid() ? "Non" : "";
        LOG0("Data ("<<  val << " Valid)");
    }
    virtual ~Data()
    {
        LOG0("Data deleted");
    }
};  // Data
///////////////////////////////////////////////////////////////////////////////////////

当使用 MSVC 编译上述代码时,会给出所需的输出,但当使用 Mingw GCC 编译器编译时,它会给出以下错误,

Base.h:1154: error: there are no arguments to 'IsNonValid' that depend on a template parameter, so a declaration of 'IsNonValid' must be available
Base.h:1553: error: 'Size' was not declared in this scope

这个问题的可能解决方案是什么?提前谢谢。

MSVC 没有正确实现两阶段名称查找。GCC 报告此错误是正确的。

原因是模板内使用的名称不依赖于模板的参数(应该在 VC 的情况下(在定义模板时查找,而不是在实例化时查找。

在您的情况下,编译器无法判断IsNonValid将来自基类,因此它理所当然地抱怨它不知道它。有两种可能的解决方案:

  1. 限定对IsNonValid的访问,以便编译器清楚它(可能(取决于模板参数:

    QString val = this->IsNonValid() ? "Non" : "";
    // or
    QString val = TYPE_LIST::IsNonValid() ? "Non" : "";
    
  2. 将继承的名称引入派生类的作用域:

    template <class TYPE_LIST>
    class Data : public TYPE_LIST
    {
    public:
      using TYPE_LIST::IsNonValid;
      // the rest as you had it originally
    

其中任何一个都会使名称依赖,从而推迟其查找,直到实际知道TYPE_LIST的值。

gcc 是正确的。您需要添加this->以将查找延迟到实例化时间。

this->IsNonValid();

MSVC 不符合要求,因为它没有正确实现两阶段名称查找,因此它将所有查找延迟到实例化时间。