在下面的代码中,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;
}
答案 0 :(得分:8)
C ++ 11解决方案
#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
类模板。只需从代码中删除它即可。没有它,你可以编写更干净的代码。
答案 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;
};