数据成员的编译时多态性

Compile-Time Polymorphism for Data Members

本文关键字:多态性 编译 数据成员      更新时间:2023-10-16

在下面的代码中,initialize()演示了一个基于编译时多态性的方法。编译的initialize()版本取决于int2type<true>int2type<false>,对于给定的模板参数T,只有其中一个为真。

恰好数据成员T* m_datum;同时适用于int2type<true>int2type<false>

现在,我想将int2type<false>版本更改为std::vector<T> m_datum;,所以我的问题是,我如何修改我的代码,使数据成员m_datumint2type<>上是多态的?

注意:请忽略下面代码背后的基本原理——相反,我想把重点放在实现数据成员的编译时多态性的机制上。

#include <type_traits>
#include <stdlib.h>
using namespace std;
template <bool n>
struct int2type
{
  enum { value = n };
};
template< typename T >
struct is_trivially_copyable
{
  static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
  public:
    Foo( size_t n ) : m_nr( n )
    {
      initialize( int2type<is_trivially_copyable<T>::value>() );        
    }
    ~Foo() { }
  private:
    void initialize( int2type<true> )
    {
      m_datum = (T*) calloc( sizeof(T), m_nr );
    }
    void initialize( int2type<false> )
    {
      m_datum = new T[m_nr];
    }
  private:
     size_t     m_nr;
     T*         m_datum;   // ok for int2type<true>
 //  vector<T>  m_datum;   // want to change to this for int2type<false>
};
class Bar
{
  public:
    Bar() { }
    virtual ~Bar() { }
};
int main(int argc, char** argv)
{
  Foo<int> foo_trivial(     5 );
  Foo<Bar> foo_nontrivial( 10 );
  return 0;
}

c++ 11解决方案,基于Nawaz的建议

#include <type_traits>
#include <vector>
#include <stdlib.h>
using namespace std;
template< typename T >
struct is_trivially_copyable
{
    static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
    private:
        static const bool what = is_trivially_copyable<T>::value;
        typedef typename std::conditional<what,T*,std::vector<T>>::type type;
    public:
        Foo( size_t n ) : m_nr( n )
        {
            initialize( m_datum );      
        }
        ~Foo() { }
    private:
        void initialize( T* dummy )
        {
            m_datum = (T*) calloc( sizeof(T), m_nr );
        }
        void initialize( std::vector<T>& dummy )
        {
            m_datum.resize( m_nr );             
        }
    private:
        size_t     m_nr;
        type       m_datum;   
};
class Bar
{
    public:
        Bar()  { }
        virtual ~Bar() { }
};
int main(int argc, char** argv)
{
    Foo<int> foo_trivial(     5 );
    Foo<Bar> foo_nontrivial( 10 );
    return 0;
}

c++ 11解

使用std::conditional作为:

#include <type_traits>
template<class T>
class Foo
{
  //some info we can use throughout the class
  static const bool what = is_trivially_copyable<T>::value;
  typedef typename std::conditional<what, T*, std::vector<T>>::type data_type;
  //data members
  data_type m_data;  //this is what you need!
}

c++ 03解

你可以编写一个元函数,并按如下方式部分特化它:

template<class T>
class Foo
{
     //primary template
     template<bool b, typename T> 
     struct get { typedef T* type; };
     //partial specialization
     template<typename T> 
     struct get<false, T> { typedef std::vector<T> type; };
     //some info we can use throughout the class
     static const bool what = is_trivially_copyable<T>::value;
     typedef typename get<what, T>::type data_type;
     //data members
     data_type m_data;  //this is what you need!
};

所以当whattrue时,data_type就会变成T*,否则就会变成std::vector<T>

在这两种情况下,您都不需要int2type类模板。只需将其从代码中删除即可。

如何:

// Generic
template <typename T, typename Arg>
struct datum_type_dispatch {};
// Specialization for Arg = int2type<true>
template <typename T>
struct datum_type_dispatch<T, int2type<true> >
{
    typedef T* type;
};
// Specialization for Arg = int2type<false>
template <typename T>
struct datum_type_dispatch<T, int2type<false> >
{
    typedef std::vector<T> type;
};
template <typename T>
class Foo
{
    // ...
private:
    // Get the datum type based on int2type<...>
    typedef typename datum_type_dispatch<T, int2type<is_trivially_copyable<T>::value> >::type datum_type;
    datum_type m_datum;
};