Полиморфизм времени компиляции для членов данных - PullRequest
7 голосов
/ 02 декабря 2011

В следующем коде 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 ]

8 голосов
/ 02 декабря 2011

C ++ 11 Solution

Использование std :: условное как:

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

Поэтому, когда what равно true, data_type превратится вбудет T*, иначе будет std::vector<T>, как требуется.

В любом случае вам не нужен шаблон класса int2type.Просто удалите это из своего кода.Вы можете написать более чистый код без него.

5 голосов
/ 02 декабря 2011

Как насчет:

// 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;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...