W poniższym kodzie initialize()
ilustruje metodę opartą na polimorfizmie kompilacji. Wersja skompilowana initialize()
zależy od int2type<true>
i int2type<false>
, z których tylko jedna będzie prawdziwa dla danego parametru szablonu T
.Polimorfizm czasu kompilacji dla danych członkowskich
Tak się składa, że element danych T* m_datum;
będzie działać zarówno dla int2type<true>
i int2type<false>
.
Teraz chcę zmienić wersję int2type<false>
do std::vector<T> m_datum;
, więc moje pytanie brzmi, jak mogę zmodyfikować mój kod tak, że element danych m_datum
jest polimorficzny na int2type<>
?
Uwaga: proszę ignorować przesłanki leżące poniżej kod - zamiast, chciałbym skupić się na mechanice osiągnięcia polimorfizm czasu kompilacji dla członków danych.
#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 rozwiązanie, oparte na zaleceniach Nawaz za
#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;
}
to bardziej konwencjonalny użyć 'type' zamiast' data_type' – Abyx
@Abyx: Tak. Zgadzam się i edytuję. :-) – Nawaz
+1: Za poznanie standardowej biblioteki nadchodzącego standardu, plus za zachęcanie do czystszego kodu przez omijanie objazdu OP "int2type <>". –