避免打开模板参数 [英] Avoid switching on template parameters

查看:114
本文介绍了避免打开模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简化我有以下类层次结构:

  class BaseVec {
public:
BaseVec ){};
virtual〜BaseVec(){};

virtual double get_double(int i)const = 0;
};

template< typename T>
class Vec:public BaseVec {
public:
Vec(){...};
〜Vec(){...};

T get(int i)const {...};

double get_double(int i)const {
return get(i);
};
};

在我的项目中,我总是得到以下形式的代码:

  template< typename T> 
double foo_template(void * p){
Vec< T> * v = reinterpret_cast< Vec T *
//使用v涉及调用get
return result;
}

double foo(void * p,int type){
if(type == 0){
return foo_template< double>(p)
} else if(type == 1){
return foo_template< int>(p);
} else if(...){
//等
} else {
//不支持类型
}
}

(我可以使用开关并使用枚举,或者先转换 p BaseVec 然后执行 dynamic_cast s,但逻辑然后保持不变)



这不是理想的维护。例如,当我添加一个额外的类,我想支持我必须添加一个子句到每个if-else-if块。



简化这个的一个可能方法是将 p 转换为 BaseVec * code>并使用 get_double 方法。然而,由于这种方法被非常频繁地调用,导致性能较差。此外,这不是可能的:有时我想调用 get 方法,因为返回的类型很重要。



我尝试了访问者模式,虽然,这有一些优点,它仍然意味着我必须为每个可能的模板参数写一个单独的代码。



是否有一些方法使这个代码更容易维护?



PS:我没有(很多)控制什么进入 foo foo 被外部程序调用(R是准确的)。因此,我只能将通用指针,int,double和character vector传递给 foo



PPS:也欢迎提供更好的标题的建议。

解决方案

C ++中的自动分派通过使用virtua函数的runtime-polymorphism和static_ast的mnas的static_type多态性发生,但你需要知道要转换的类型。



使用不同的设计,避免 void * ,您可以执行以下操作:

  template< class Derived> 
class static_polimorphic {};

template< class A>
A& upcast(static_polymorphic< A& sa)
{return static_cast< A&>(sa); }

template< class A>
const A& upcast(const static_polymorphic< A& sa)
{return static_cast< const A&>(sa); }

现在你的类像

  class C1:public static_polymorphic< C1> 
{
....
};

class C2:public static_polymorphic< C2>
{
....
};

多态性将应用为

  template< class A> 
void function(const static_polymorphic< A& sa)
{
A& a = upcast(sa);
a.methods();
...
}

换句话说,



请注意,作为由派生类型区分的基础,公共函数不会重新变为虚拟变量。您可以完全避免基于运行时的多态性,除非您必须将不同的运行时类型创建的对象存储到同一个容器或集合中。



为此,您可以使用第二非虚拟化基础与抽象虚拟函数作为发射器为派生类中的一个。
(可能更好地使用运行时多态性作为第一个基础,以简化运行时指针转换,因为将没有偏移)


Simplified I have the following class hierarchy:

class BaseVec {
  public:
    BaseVec() {};
    virtual ~BaseVec() {};

    virtual double get_double(int i) const = 0;
};

template<typename T>
class Vec : public BaseVec {
  public:
    Vec() { ... };
    ~Vec() { ... };

    T get(int i) const { ... };

    double get_double(int i) const {
      return get(i);
    };
};

In my project I repeatedly end up with code of the following form:

template<typename T>
double foo_template(void* p) {
  Vec<T>* v = reinterpret_cast<Vec<T>*>(p);
  // use v which involves calling get
  return result;
}

double foo(void* p, int type) {
  if (type == 0) {
    return foo_template<double>(p);
  } else if (type == 1) {
    return foo_template<int>(p);
  } else if (...) {
    // etc.
  } else {
    //unsupported type
  }
}

(I could use a switch and use enums, or first cast p to BaseVec and then do dynamic_casts, but the logic then remains the same)

This is not ideal to maintain. For example when I add an additional class I want to support I have to add a clause to each of the if-else-if blocks.

One possible way of simplifying this would be to cast p to BaseVec* and use the get_double method. However, since this method is called very often this results in poor performance. Furthermore, this is not alway possible: sometimes I want to call the get method as the type returned is important.

I experimented with the visitor-pattern, and although, this has some advantages, it still means I have to write a seperate piece of code for each possible template parameter.

Is there some way of making this code easier to maintain?

PS: I don't have (much) control over what comes into foo. foo gets called by an external programme (R to be exact). Therefore, I can only pass generic pointers, int, doubles and character vectors to foo.

PPS: Suggestions for a better title are also welcome.

解决方案

Automatic dispatch in C++ happens with runtime-polymorphism by means of virtua function and with static_type polymorphism by mnas of a static_Cast, but you need to know what type to cast.

With a different design, avoiding void*, you can do the following:

template<class Derived>
class static_polimorphic {};

template<class A>
A& upcast(static_polymorphic<A>& sa)
{ return static_cast<A&>(sa); }

template<class A>
const A& upcast(const static_polymorphic<A>& sa)
{ return static_cast<const A&>(sa); }

Now, you classes shold be like

class C1: public static_polymorphic<C1>
{
 ....
};

class C2: public static_polymorphic<C2>
{
 ....
};

Polymorphism will then apply as

template<class A> 
void function(const static_polymorphic<A>& sa)
{
   A& a = upcast(sa);
   a.methods();
   ...
}

In other words, the type is anymore represented a base member variable, but by a base template parameter.

Note also that being the bases differentiated by the derived type, common functions will not reaqire to be virtual. You can so completely avoid runtimes-based polymorphism, unless you have to store different runtime-type created object into a same container or collection.

For that purpose you can use a second non-tempetised base with abstract virtual function as "launchers" for the one in the derived classes. (May be better to use the runtime polymorphic one as first base, to simplify run-time pointer convertion, since there will be no offset)

这篇关于避免打开模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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