读书人

关于trait跟policy的互操作

发布时间: 2012-10-30 16:13:36 作者: rapoo

关于trait和policy的互操作
近日写模板的时候遇到一个问题,与trait和policy之间的互操作有关,下面是简化后的代码:

C/C++ code
template < typename T >class   TraitSet;template<>class TraitSet< int >{    public:        typedef int TypeT;};template<>class TraitSet< long >{    public:        typedef long TypeT;};.................        //有很多traittemplate< typename T >class DefaultAction{    public :        ............        static T GetData( void )        {            if( typeid( T ) == typeid( int ) )            {                return 10;            }            if( typeid( T ) == typeid( long ) )            {                return 20;            }            ..................... //有很多个typeid            return T( );        }        ...............};........................    //有一些policy,每个policy都有GetDatatemplate<   typename T,            typename Policy =   DefaultAction< T >,            template < typename > class Trait   =   TraitSet >class ResultSet{    public :        ..............        static T GetResult( void )        {            ..............            typename Trait<T>::TypeT    Data    =   Policy::GetData( );            ...............            return Data;        }        ............};

在ResultSet::GetResult中需要给Data赋值,其值与不同的policy和不同的trait都有关,在Policy::GetData中需要根据不同的trait返回不同的内容。我只想到了在Policy::GetData内部使用typeid分辨不同的trait,由于有很多trait,造成每个policy都有一大串typeid,这写法太丑陋了,使用运行时RTTI也有点不爽,请问各位有否代码更优雅的意见?

[解决办法]
推荐一下,值得研究一把~
[解决办法]
C/C++ code
template<>class TraitSet< int >{    public:        typedef int TypeT;    enum { res = 10 };};template<>class TraitSet< long >{    public:        typedef long TypeT;        enum { res = 2 };};template< typename T,template < typename > class Trait   =   TraitSet  >class DefaultAction{    public :        typedef Traits<T> traits;//把这个代入到ResultSet        ............        static T GetData( void )        {            return traits::res;        }        ...............};
[解决办法]
可以对 policy 也特化吧,例如这样。
C/C++ code
template <typename T> struct TraitSet;template <> struct TraitSet <int > { typedef int  TypeT; };template <> struct TraitSet <long> { typedef long TypeT; };template <typename T> struct DefaultAction { static T GetData () { return T(); } };template <> struct DefaultAction <int > { static int GetData () { return 10; } };template <> struct DefaultAction <long> { static int GetData () { return 20; } };// same thing for OtherAction.
[解决办法]
不清楚楼主的具体需求

用映射应该是比较好的方案吧. 如楼上,,
更通用地可以考虑 Type 到 类类型静态对象的映射.

个人比较看好表驱动.
[解决办法]
>这写法太丑陋了,使用运行时RTTI也有点不爽
杀掉RTTI,在编译器间作选择的方法
std::is_same<T1, T2>::value //(bool value)

如果你的编译器不支援std::is_same

C/C++ code
template<typename T1, typename T2>class is_same{  public:    enum {value = 0};}template<typename T>class is_same<T, T>{  public:    enum {value = 1};};
[解决办法]
lz 忘了可以特化 类成员函数么
C/C++ code
template < typename T >class   TraitSet;template<>class TraitSet< int >{public:    typedef int TypeT;};template<>class TraitSet< long >{public:    typedef long TypeT;};template< typename T >class DefaultAction{public :    static T GetData( void );};template<>int DefaultAction<int>::GetData(){    return 10;}template<>long DefaultAction<long>::GetData(){    return 20;}int main(){    printf( "%d\n" , DefaultAction<int>::GetData() );    printf( "%d\n" , DefaultAction<long>::GetData() );    return 0;} 


[解决办法]
要去掉丑陋的RTTI,需要函数重载或虚函数

C/C++ code
#include <iostream>template <typename T>class Traits{public:    typedef T value_type;};//重载以去掉RTTIstruct Action1{    static void getData(int& value)    {        value = 10;    }    static void getData(char& value)    {        value = 20;    }    //....};struct Action2{    static void getData(int& value)    {        value = 30;    }    static void getData(char& value)    {        value = 20;    }    //....};template<typename T,  typename policy, template <typename> class traits>struct ResultSet{    static typename traits<T>::value_type getData()     {         typename traits<T>::value_type val;         policy::getData(val);         return val;     }};int main(int, char* []){    std::cout << ResultSet<int, Action1, Traits>::getData() << std::endl;    std::cout << ResultSet<char, Action2,  Traits>::getData() << std::endl;    return 0;}
[解决办法]
>lz 忘了可以特化 类成员函数么
这点我上面提过了,其实楼主的问题连is_same都用不到


>要去掉丑陋的RTTI,需要函数重载或虚函数
虽然可以解决问题,但使用virtual会带来执行期间的负担
overload连没有使用的代码都会被具现化

如果追求的是完全的"编译期的运算"(楼主的目标?)
照19楼的写法就好了
简单(虽然建表有点麻烦,可考虑macro)
而且没有呼叫的type就不会被具现化
有可能可以生成较小的二进制码

忘了说,除了C++11,boost也有提供type_traits
此外,虽然很遗憾,但是这类技巧大概不适合拿来和别人共事吧
[解决办法]
探讨

可以对 policy 也特化吧,例如这样。
C/C++ code

template <typename T> struct TraitSet;
template <> struct TraitSet <int > { typedef int TypeT; };
template <> struct TraitSet <long> { typedef long TypeT; };

tem……

[解决办法]
楼主是花太多时间在C++标准上了,而没有去看《modern c++ design》?
type2type、type2int的映射是个极简单的活啊。
另外,trait是一种policy
[解决办法]
在你的例子里是一样的。
[解决办法]
探讨

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容易造成程序体积问题的。这也是偶一开始想避免的问题,只是,没有考虑到象8楼那样仅对RTTI部分全特化。

[解决办法]
探讨

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容易造成程序体积问题的。这也是偶一开始想避免的问题,只是,没有考虑到象8楼那样仅对RTTI部分全特化。

[解决办法]
>在policy上做全特化很容易造成程序体积问题的
以你的例子来看,回传的结果应该都是编译期间的常数吧?
这怎么会造成体积膨胀呢?

int A = DefaultAction<int>::GetData(); //等同于int A = 10;
迟点再用asm确定一下,有那个人可以帮忙确定的吗?

C/C++ code
template<>int DefaultAction<int>::GetData(){    return 10;}
[解决办法]
探讨

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容易造成程序体积问题的。这也是偶一开始想避免的问题,只是,没有考虑到象8楼那样仅对RTTI部分全特化。

[解决办法]
g++-4.7 -O3 试了个小例子。
C/C++ code
template <typename T> struct TraitSet;template <> struct TraitSet <int > { typedef int  TypeT; };template <> struct TraitSet <long> { typedef long TypeT; };template <typename T> struct DefaultAction { static T GetData () { return T(); } };template <> struct DefaultAction <int > { static int GetData () { return 10; } };template <> struct DefaultAction <long> { static int GetData () { return 20; } };template<   typename T,typename Policy =   DefaultAction< T >,template < typename > class Trait   =   TraitSet >struct ResultSet{ public :   static T GetResult( void )   {    typename Trait<T>::TypeT    Data    =   Policy::GetData( );    return Data;   }};#include <iostream>int main (){ std::cout << ResultSet<int >::GetResult() << std::endl; std::cout << ResultSet<long>::GetResult() << std::endl; return 0;} 


[解决办法]
特化什么的在楼主的需求里,代价是大了点.要多写好几个字母,而且费脑子.直接重载就可以了....

C/C++ code
template <typename _T>class xxx {  inline int _getdata( int * ) { return 1; }  inline long _getdata( long * ) { return 2; }  inline _T _getdata( ... ) { return _T(); }public:  _T GetData() { return _getdata( (_T*)0 ); }};
[解决办法]
无论你怎么简化的代码,根据类型执行不同代码的框架还在啊.
所以,无论是特化,还是重载,还是其它什么方式,都可以满足这个要求吧.
[解决办法]
探讨

引用:

引用:

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容易造成程序体积问题的。这也是偶一开始想避免的问题,只是,没有考虑到象8楼那样仅对RTTI部分全特化。

表示很困惑。语言要……

[解决办法]
编辑不了,能把上面那个删了不?
C/C++ code
#include <boost/mpl/vector.hpp>#include <boost/mpl/vector_c.hpp>#include <boost/mpl/map.hpp>#include <boost/mpl/at.hpp>#include <boost/mpl/find.hpp>#include <boost/mpl/begin.hpp>#include <boost/mpl/distance.hpp>#include <boost/static_assert.hpp>#include <boost/type_traits/is_same.hpp>namespace boost{namespace mpl {}}namespace mpl = boost::mpl;struct myclass{    explicit myclass(int){};};typedef mpl::vector<int,long,char,double,myclass,long *> types;template<typename T,typename traint,typename policy>struct ResultSet{        typedef typename mpl::at<traint,T>::type type;        typedef typename mpl::distance<typename mpl::begin<types>::type,typename mpl::find<types,type>::type >::type pos;    static const int value = mpl::at_c<policy,pos::value>::type::value;};typedef mpl::map5<mpl::pair<int,int>,mpl::pair<long,long>,mpl::pair<char,char>,mpl::pair<double,double>,mpl::pair<myclass,myclass> > traint1; typedef mpl::map5<mpl::pair<int,int*>,mpl::pair<long,long*>,mpl::pair<char,char*>,mpl::pair<double,double*>,mpl::pair<myclass,myclass*> > traint2;typedef mpl::map5<mpl::pair<int,long>,mpl::pair<long,char>,mpl::pair<char,double>,mpl::pair<double,myclass>,mpl::pair<myclass,int> > traint3;typedef mpl::vector_c<int,1,2,3,4,5,6> policy1;typedef mpl::vector_c<int,10,20,30,40,50,60> policy2;typedef ResultSet<long,traint1,policy1> tst1;    //identify,long,2BOOST_STATIC_ASSERT(( boost::is_same<tst1::type,long>::value ));BOOST_STATIC_ASSERT(( tst1::value == 2 ));typedef ResultSet<long,traint2,policy1> tst2;    //pointer,long *,6BOOST_STATIC_ASSERT(( boost::is_same<tst2::type,long *>::value ));BOOST_STATIC_ASSERT(( tst2::value == 6 ));typedef ResultSet<myclass,traint1,policy2> tst3;    //identify,myclass,50BOOST_STATIC_ASSERT(( boost::is_same<tst3::type,myclass>::value ));BOOST_STATIC_ASSERT(( tst3::value == 50 ));typedef ResultSet<myclass,traint3,policy2> tst4;    //next,int,10BOOST_STATIC_ASSERT(( boost::is_same<tst4::type,int>::value ));BOOST_STATIC_ASSERT(( tst4::value == 10 ));typedef ResultSet<double,traint3,policy1> tst5;    //next,myclass,5BOOST_STATIC_ASSERT(( boost::is_same<tst5::type,myclass>::value ));BOOST_STATIC_ASSERT(( tst5::value == 5 ));int main(){}
[解决办法]
探讨

引用:
引用:

引用:

引用:

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容易造成程序体积问题的。这也是偶一开始想避免的问题,只是,没有考虑到象……

------解决方案--------------------


探讨

引用:

引用:

引用:
引用:

引用:

引用:

7楼、10楼、19楼:

policy最好还是不要做全特化,特别是我这个例子,因为policy跟trait不一样,trait一般而言不含有实体代码,而policy正好相反,在policy上做全特化很容……

[解决办法]
借用8楼的思路
C/C++ code
namespace for_actions{    template<typename T>    struct def_value    {        T value;    };        template<>    struct def_value<int>    {        enum{value = 10};        };        template<>    struct def_value<long>    {        enum{value = 20};        };}template< typename T >class DefaultAction{public :    typedef for_actions::def_value<T> data_reader;};struct A{    A(const std::string& s);};namespace for_actions{    template<>    struct def_value<A>    {        A value;                def_value()            : value("构造你妹")        {}    };    }int main(){    DefaultAction<A>::data_reader().value;    std::system("pause");}/////////////////////        static T GetResult( void )        {            ..............            typename Trait<T>::TypeT    Data    =   typename Policy::data_reader().value;            ...............            return Data;        }
[解决办法]
探讨
近日写模板的时候遇到一个问题,与trait和policy之间的互操作有关,下面是简化后的代码:

C/C++ code

template < typename T >
class TraitSet;

template<>
class TraitSet< int >
{
public:

typedef int TypeT;
};

template<>
cla……

读书人网 >C++

热点推荐