Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-Time Polymorphism for Data Members

In the following code, initialize() illustrates a method based on compile-time polymorphism. The version of initialize() compiled depends on int2type<true> and int2type<false>, only one of which will be true for a given template parameter T.

It just so happens that data member T* m_datum; will work for both int2type<true> and int2type<false>.

Now, I want to change the int2type<false> version to std::vector<T> m_datum;, so my question is, how do I modify my code so that the data member m_datum is polymorphic on int2type<>?

Note: please ignore the rationale behind the code below - instead, I would like to focus on the mechanics of achieving compile-time polymorphism for data members.

#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 solution, based on Nawaz's recommendations

#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;
}
like image 502
kfmfe04 Avatar asked Dec 02 '11 11:12

kfmfe04


1 Answers

C++11 Solution

Use std::conditional as:

#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 Solution

You can write a metafunction and partially specialize this as follows:

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

So when what is true, data_type will turn out to be T*, or else it will be std::vector<T>, as desired.

In either case, you don't need int2type class template. Just remove that from your code. You can write cleaner code, without it.

like image 164
Nawaz Avatar answered Nov 06 '22 03:11

Nawaz