数据成员的编译时多态性

时间:2011-12-02 11:42:47

标签: c++ templates polymorphism c++11

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

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

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

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

#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;
}

2 个答案:

答案 0 :(得分:8)

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类模板。只需从代码中删除它即可。没有它,你可以编写更干净的代码。

答案 1 :(得分:5)

怎么样:

// 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;
};