C ++和typetrits:定义可能定义列表的最简单方法 [英] C++ and typetraits: simplest way of defining a list of possible definitions

查看:165
本文介绍了C ++和typetrits:定义可能定义列表的最简单方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要定义一个函数 template< typename T> T constCast(const ScriptVar_t& s); 。根据 T ,我想要有不同的定义。 ( ScriptVar_t 是一个类,但在此上下文中的细节不重要。)



T 不像特定类型那么简单,它们都是更复杂的静态布尔表达式。也就是说我有一个表达式的列表 ext1 .. extN ,对于每个,我有一个函数的定义。我想让它们检查顺序和第一个匹配表达式的定义应该使用。如果所有的失败,我想得到一个编译器错误。



现在,我只有2个定义,我的代码看起来像这样(这是一个完整的测试用例,相关代码被标记):

  #include< boost / type_traits.hpp> 

枚举{
SVT_INT,
SVT_FLOAT,
SVT_BASEOBJ,
SVT_CUSTOMVAR
};

struct BaseObject {};
struct CustomVar {};

template< typename T> struct GetType;
模板<> struct GetType< int> {static const int value = SVT_INT; };
模板<> struct GetType< float> {static const int value = SVT_FLOAT; };
模板<> struct GetType< BaseObject> {static const int value = SVT_BASEOBJ; };

template< bool> struct GetType_BaseCustomVar;
模板<> struct GetType_BaseCustomVar< true> {
struct Type {static const int value = SVT_CUSTOMVAR; };
};
template< typename T> struct GetType:GetType_BaseCustomVar< boost :: is_base_of< CustomVar,T> :: value> :: Type {};

struct ScriptVar_t;
template< typename T> T CastScriptVarConst(const ScriptVar_t& s);

struct ScriptVar_t {
operator int()const {return 0; }
operator float()const {return 0.0f; }
运算符BaseObject()const {return BaseObject(); }
template< typename T> T * as()const {return NULL; }

template< typename T> T castConst()const {return CastScriptVarConst< T>(* this); }
};

// ***相关代码从这里开始

模板< typename T> T CastScriptVarConst(const ScriptVar_t& s);

template< bool> struct CastScriptVar1;
template< typename T> struct CastScriptVar1_IsSimpleType {
static const bool value = GetType< T> :: value< SVT_BASEOBJ;
};
模板<> struct CastScriptVar1< true> {
template< typename T> static T castConst(const ScriptVar_t& s,const T& / * dummy * /){return(T) }
};

template< bool> struct CastScriptVar2;
template< typename T> struct CastScriptVar2_IsCustomVar {
static const bool value = boost :: is_base_of< CustomVar,T> :: value;
};
模板<> struct CastScriptVar2< true> {
template< typename T> static T castConst(const ScriptVar_t& s,const T& / * dummy * /){return * s.as T }
};

模板<> struct CastScriptVar1< false> {
template< typename T> static T castConst(const ScriptVar_t& s,const T& / * dummy * /){
return CastScriptVar2< CastScriptVar2_IsCustomVar< T> :: value> :: castConst(s,T
}
};
template< typename T> T CastScriptVarConst(const ScriptVar_t& s){
return CastScriptVar1< CastScriptVar1_IsSimpleType< T> :: value> :: castConst(s,T());
}

int main(){
ScriptVar_tv;
v.castConst< int>();
v.castConst< CustomVar>();
}



我经过几次尝试后想出了这一点,直到它工作。



(从代码中可以看出,两个表达式分别是 GetType< T> :: value< SVT_BASEOBJ code> boost :: is_base_of< CustomVar,T> :: value 。如果两者都为假,编译器应该抛出一个错误,但这只是我的问题的一个例子) p>

我不知道这个代码是否有更清洁的解决方案。






为了参考,我在玩这里

解决方案

如果我的理解正确,我会发现, d使用
cast-functors的查找表和一个元函数来计算
表中的偏移量。



将使用由标签和函子的
组成的基于类型的查找表。 pick_cast 会选择正确的标签
,而不是 int 。如果决定
表变大,这可能更容易阅读。

  #include< boost / type_traits.hpp> ; 
#include< boost / mpl / int.hpp>
#include< boost / mpl / vector.hpp>
#include< boost / mpl / if.hpp>
#include< boost / mpl / at.hpp>

struct BaseObject {};
structure CustomVar {};

命名空间mpl = boost :: mpl;

struct ScriptVar_t {
operator int()const {return 0; }
operator float()const {return 0.0f; }
operator BaseObject()const {return BaseObject(); }
template< typename T> T * as()const {return NULL; }
template< typename T> T castConst()const;
};

struct default_cast {
template< typename T>
T operator()(const ScriptVar_t& s)const {return(T)s; }
};

struct base_cast {
template< typename T>
T operator()(const ScriptVar_t& s)const {return * s.as< T& }
};

typedef mpl :: vector< default_cast,base_cast>铸造

枚举{
DEFAULT = 0,
BASE,
END_OF_ENUM
};

//为T
选择合适的转换模板< typename T>
struct pick_cast {
typedef typename mpl :: if_< typename boost :: is_base_of< CustomVar,T> :: type,
mpl :: int_< BASE> ;, mpl :: int_< DEFAULT> > :: type类型;
};

template< typename T> T ScriptVar_t :: castConst()const {
typedef typename mpl :: at< casts,typename pick_cast< T> :: type> :: type func;
return func()。template operator()< T>(* this);
}

int main(){
ScriptVar_t v;
v.castConst< int>();
v.castConst< CustomVar>();
}


I want to define a function template<typename T> T constCast(const ScriptVar_t& s);. Depending on T, I want to have different definitions. (ScriptVar_t is a class but details are not important here in this context.)

The conditions on T aren't as simple as specific types, they are all somewhat more complicated static boolean expressions. I.e. I have a list of expressions ext1..extN and for each, I have a definition of that function. And I want to have them checked in that order and the definition of the first matching expression should be used. If all of them fail, I want to get a compiler error.

Right now, I just have 2 definitions and my code looks like this (this is a full test case, the relevant code is marked):

#include <boost/type_traits.hpp>

enum {
    SVT_INT,
    SVT_FLOAT,
    SVT_BASEOBJ,
    SVT_CUSTOMVAR
};

struct BaseObject {};
struct CustomVar {};

template<typename T> struct GetType;
template<> struct GetType<int> { static const int value = SVT_INT; };
template<> struct GetType<float> { static const int value = SVT_FLOAT; };
template<> struct GetType<BaseObject> { static const int value = SVT_BASEOBJ; };

template<bool> struct GetType_BaseCustomVar;
template<> struct GetType_BaseCustomVar<true> {
    struct Type { static const int value = SVT_CUSTOMVAR; };
};
template<typename T> struct GetType : GetType_BaseCustomVar<boost::is_base_of<CustomVar,T>::value>::Type {};

struct ScriptVar_t;
template<typename T> T CastScriptVarConst(const ScriptVar_t& s);

struct ScriptVar_t {
    operator int() const { return 0; }
    operator float() const { return 0.0f; }
    operator BaseObject() const { return BaseObject(); }
    template<typename T> T* as() const { return NULL; }

    template <typename T> T castConst() const { return CastScriptVarConst<T>(*this); }
};

// *** relevant code starts here

template<typename T> T CastScriptVarConst(const ScriptVar_t& s);

template<bool> struct CastScriptVar1;
template<typename T> struct CastScriptVar1_IsSimpleType {
    static const bool value = GetType<T>::value < SVT_BASEOBJ;
};
template<> struct CastScriptVar1<true> {
    template<typename T> static T castConst(const ScriptVar_t& s, const T& /*dummy*/) { return (T) s; }
};

template<bool> struct CastScriptVar2;
template<typename T> struct CastScriptVar2_IsCustomVar {
    static const bool value = boost::is_base_of<CustomVar,T>::value;
};
template<> struct CastScriptVar2<true> {
    template<typename T> static T castConst(const ScriptVar_t& s, const T& /*dummy*/) { return *s.as<T>(); }
};

template<> struct CastScriptVar1<false> {
    template<typename T> static T castConst(const ScriptVar_t& s, const T& /*dummy*/) {
        return CastScriptVar2<CastScriptVar2_IsCustomVar<T>::value>::castConst(s, T());
    }
};
template<typename T> T CastScriptVarConst(const ScriptVar_t& s) {
    return CastScriptVar1<CastScriptVar1_IsSimpleType<T>::value>::castConst(s, T());
}

int main() {
    ScriptVar_t v;
    v.castConst<int>();
    v.castConst<CustomVar>();
}

I came up with this after a few tries until it works.

(As you can see from the code, the two expressions are GetType<T>::value < SVT_BASEOBJ and boost::is_base_of<CustomVar,T>::value. If both are false, the compiler should throw an error. But this is only an example for my question.)

I wonder if there is a somewhat more clean solution for this code.


For reference, I am playing with it here. And right now, I have again a somewhat different solution to all the other solutions here.

解决方案

If I understood correctly, I'd use a look-up table for the cast-functors and a meta-function to calculate the offset into the table.

An alternative would be to use a type based look-up table consisting of tags and functors. pick_cast would then choose the right tag instead of an int. This might be easier to read if the decision table becomes large.

#include <boost/type_traits.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/at.hpp>

struct BaseObject {};
struct CustomVar {};

namespace mpl = boost::mpl;

struct ScriptVar_t {
    operator int() const { return 0; }
    operator float() const { return 0.0f; }
    operator BaseObject() const { return BaseObject(); }
    template<typename T> T* as() const { return NULL; }
    template <typename T> T castConst() const;
};

struct default_cast {
  template<typename T>
  T operator()(const ScriptVar_t& s) const { return (T) s; }
};

struct base_cast {
  template<typename T>
  T operator()(const ScriptVar_t& s) const { return *s.as<T>(); }
};

typedef mpl::vector< default_cast, base_cast > casts;

enum {
  DEFAULT = 0,
  BASE,
  END_OF_ENUM
};

// pick the right cast for T
template<typename T>
struct pick_cast {
  typedef typename mpl::if_< typename boost::is_base_of<CustomVar,T>::type,
                             mpl::int_<BASE>, mpl::int_<DEFAULT> >::type type;
};

template <typename T> T ScriptVar_t::castConst() const { 
  typedef typename mpl::at<casts, typename pick_cast<T>::type>::type func;
  return func().template operator()<T>(*this);
}

int main() {
    ScriptVar_t v;
    v.castConst<int>();
    v.castConst<CustomVar>();
}

这篇关于C ++和typetrits:定义可能定义列表的最简单方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆