【问题标题】:C++ class template of specific baseclass特定基类的 C++ 类模板
【发布时间】:2010-01-06 12:46:52
【问题描述】:

假设我有课程:

class Base{};

class A: public Base{
    int i;
};

class B:public Base{
    bool b;
};

现在我想定义一个模板类:

template < typename T1, typename T2 >
class BasePair{
    T1 first;
    T2 second;
};

但我想将其定义为只有 Base 类的后代可以用作模板参数。

我该怎么做?

【问题讨论】:

  • 您需要更正模板语法。你的意思是A和B是私人派生的吗?

标签: c++ generics inheritance templates


【解决方案1】:

C++11 引入&lt;type_traits&gt;

template <typename T1, typename T2>
class BasePair{
static_assert(std::is_base_of<Base, T1>::value, "T1 must derive from Base");
static_assert(std::is_base_of<Base, T2>::value, "T2 must derive from Base");

    T1 first;
    T2 second;
};

【讨论】:

    【解决方案2】:

    更准确地说:

    class B {};
    class D1 : public B {};
    class D2 : public B {};
    class U {};
    
    template <class X, class Y> class P {
        X x;
        Y y;
    public:
        P() {
            (void)static_cast<B*>((X*)0);
            (void)static_cast<B*>((Y*)0);
        }
    };
    
    int main() {
        P<D1, D2> ok;
        P<U, U> nok; //error
    }
    

    【讨论】:

      【解决方案3】:

      C++ 还不允许直接这样做。您可以通过在类中使用STATIC_ASSERTtype checking 来间接实现它:

      template < typename T1, typename T2 >
      class BasePair{
          BOOST_STATIC_ASSERT(boost::is_base_of<Base, T1>);
          BOOST_STATIC_ASSERT(boost::is_base_of<Base, T2>);
          T1 first;
          T2 second;
      };
      

      【讨论】:

      • 我不希望参数只是具有相同的基类 - 我希望它们具有我的特定类 Base 作为基类
      • 关键字是“还”。为了其他从搜索引擎到达这里的人的利益,static_assertis_base_of 毕业到 C++11 中的官方语言功能。它们生成的代码比公认的答案更直观/更不可怕。
      【解决方案4】:

      这是一个很好的问题!在通过link 进行研究时,我想出了以下内容,诚然,这与那里提供的解决方案没有太大区别。每天学习一些东西...检查!

      #include <iostream>
      #include <string>
      #include <boost/static_assert.hpp>
      
      using namespace std;
      
      template<typename D, typename B>
      class IsDerivedFrom
      {
        class No { };
        class Yes { No no[3]; };
      
        static Yes Test(B*); // declared, but not defined
        static No Test(...); // declared, but not defined
      
      public:
        enum { IsDerived = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
      };
      
      
      class Base
      {
      public:
          virtual ~Base() {};
      };
      
      class A : public Base
      {
          int i;
      };
      
      class B : public Base
      {
          bool b;
      };
      
      class C
      {
          string z;
      };
      
      
      template <class T1, class T2>
      class BasePair
      {
      public:
          BasePair(T1 first, T2 second)
              :m_first(first),
               m_second(second)
          {
              typedef IsDerivedFrom<T1, Base> testFirst;
              typedef IsDerivedFrom<T2, Base> testSecond;
      
              // Compile time check do...
              BOOST_STATIC_ASSERT(testFirst::IsDerived == true);
              BOOST_STATIC_ASSERT(testSecond::IsDerived == true);
      
              // For runtime check do..
              if (!testFirst::IsDerived)
                  cout << "\tFirst is NOT Derived!\n";
              if (!testSecond::IsDerived)
                  cout << "\tSecond is NOT derived!\n";
      
          }
      
      private:
          T1 m_first;
          T2 m_second;
      };
      
      
      int main(int argc, char *argv[])
      {
          A a;
          B b;
          C c;
      
          cout << "Creating GOOD pair\n";
          BasePair<A, B> good(a, b);
      
          cout << "Creating BAD pair\n";
          BasePair<C, B> bad(c, b);
          return 1;
      }
      

      【讨论】:

        【解决方案5】:
        class B
        {
        };
        class D : public B
        {
        };
        class U
        {
        };
        
        template <class X, class Y> class P
        {
            X x;
            Y y;
        public:
            P()
            {
                (void)static_cast<X*>((Y*)0);
            }
        };
        

        【讨论】:

        • 请解释一下.. 这如何保证模板参数是 B 的后代?
        • 当你实例化模板 P ok;编译器将尝试使用 static_cast 模板函数将 D 类型指针转换为 B 类型指针。这可以正常工作,但在 P nok 的情况下;此转换失败,您将收到编译器错误(错误 C2440: 'static_cast' : cannot convert from 'U ' to 'B')。此外,这不会有任何运行时影响(代码并不慢)。它是静态或编译时类型检查。
        【解决方案6】:

        首先,修正声明

        template < class T1, class T2 >
        class BasePair{
            T1 first;
            T2 second;
        };
        

        然后,您可以在基类中声明一些私有函数 Foo();并告诉 Base 类有 BasePair 作为朋友;然后在朋友构造函数中你只需要调用这个函数。这样,当有人试图将其他类用作模板参数时,您将得到编译时错误。

        【讨论】:

        • “修正声明”——你也一样。 ;-)
        【解决方案7】:

        在未知(雅虎)建议的答案中,实际上不需要将类型 X 和 Y 的变量作为成员。这些行在构造函数中就足够了:

        static_cast<B*>((X*)0);
        static_cast<B*>((Y*)0);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-04-01
          • 1970-01-01
          • 2021-12-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多