【问题标题】:std::is_base_of() depthstd::is_base_of() 深度
【发布时间】:2013-02-26 13:22:55
【问题描述】:

我有这样的层次结构:

namespace MyService{
class IBase
{
public:
    virtual ~IBase(){}

protected:
    IPointer *_somePointer;

};
}


class IInterface: public MyService::IBase
{
public:
    virtual ~IInterface(){}

    virtual std::string get() const = 0;
};


class ConcreteClass: public IInterface
{
public: 
    std::string get() const
    {
        bool isNull = (_somePointer == NULL);
        return "Hello";
    }
};


bool isBase = std::is_base_of<IBase, ConcreteClass>::value;

我需要检查 I3 是从 I1 派生的。但是 std::is_base_of() 对我来说效果不佳 - 它返回错误。 目标是添加到任何类 IBase 并检查任何类是否存在 IBase 层次结构

找到了问题,但没有解决。我的代码是:

template<class Base, class Derived>
    bool IsDerivedFromBase()
    {
        if( std::tr1::is_fundamental<Base>::value )
            throw MyService::Exceptions::ETypeTraitsInvalidArgument( "Base class can't be POD" );
        if( std::tr1::is_fundamental<Derived>::value )
            throw MyService::Exceptions::ETypeTraitsInvalidArgument( "Derived class can't be POD" );

        bool a = std::tr1::is_base_of<Base, Derived>::value;
        return a;
    }

我也有这样的

bool a = std::is_base_of<MyService::IBase, SomeInterface>::value; // true
a = IsDerivedFromBase<MyService::IBase, SomeInterface>(); // false

【问题讨论】:

  • g++ 4.7.2 的行为符合预期:ideone.com/8yrx6k
  • Clang 4.0 的行为符合预期。
  • 请下次提供重现问题的可编译代码。只需编译您的代码,您就会发现它在语法上不正确。
  • 你的类型是否完整?
  • 仍然有效:ideone.com/RfDuPr

标签: c++ c++11


【解决方案1】:

这确实会在 G++ 4.7 中输出 true:

class I1{};
class I2: public I1{};
class I3: public I2{};

int main(int argc, const char* argv[])
{
  std::cout << std::boolalpha
            << std::is_base_of<I1, I3>::value
            << std::endl;
  return 0;
}

注意std::is_base_of&lt;I1, I3&gt;::value等价于实例化std::is_base_of&lt;I1, I3&gt;类型的对象并将其转换为bool。

我相信这样做是准确的。 std::is_base_of&lt;Base, Derived&gt; 被定义为具有条件(§20.9.6):

Base 是 Derived (10) 的基类,不考虑 cv-qualifiers 或 Base 和 Derived 不是联合,并且在不考虑 cv-qualifiers 的情况下命名相同的类类型

基类是这样定义的(§10):

如果类B 是D 的直接基类或D 的基类之一的直接基类,则它是类D 的基类。

所以是的,I1 是 I3 的基类,std::is_base_of&lt;I1, I3&gt;::value 应该是 true。

【讨论】:

    【解决方案2】:

    No, the code works:

    #include <iostream>
    #include <type_traits>
    
    class A {};
    class B : public A {};
    class C : public B {};
    
    int main() {
        std::cout << std::boolalpha;
        std::cout << "a2b: " << std::is_base_of<A, B>() << '\n';
        std::cout << "b2a: " << std::is_base_of<B, A>() << '\n';
        std::cout << "c2b: " << std::is_base_of<C, B>() << '\n';
        std::cout << "a2c: " << std::is_base_of<A, C>() << '\n';
    }
    

    产量:

    a2b: true
    b2a: false
    c2b: false
    a2c: true
    

    以上适用于 GCC 4.6 和 4.7。如果您使用的是其他东西,则需要指定。

    你的错误一定在别处。

    【讨论】:

      【解决方案3】:

      我发现了问题。 我有一些带有单元测试的 .cpp 文件,我在其中定义了同名的本地类。 还没有找到标准的tis,但是复制代码是这样的:

      /// 1.cpp
      class IInterface{};
      class Interface: public IInterface{};
      
      /// class 2.cpp
      class IInterface: public MyService:IBase{};
      class Interface: public IInterface{};
      
      /// facility.h
      namespace a{ namespace b{
          template<class T, class B>
          bool IsBaseOf(){
              return std::is_base_of<T, B>();
          }
      }
      }
      }
      
      /// ...main
      a::b::IsBaseOf<MyService::IBase, Interface>();
      

      它应该/可能会失败。但是,如果我让类名唯一就可以了。

      【讨论】:

      • 这段代码无效,它违反了一个定义规则,类名必须在整个程序中是唯一的
      • 它不能不编译它,错误发生在单独编译的不同文件中,这就是C++的工作原理。 “我的代码编译”与“我的代码正确”不同,这也是 C++ 的工作原理。 ODR 说你的程序有undefined-behaviour,这不是意味着它应该无法编译。
      猜你喜欢
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多