【问题标题】:How to convert template classes?如何转换模板类?
【发布时间】:2013-06-21 12:02:33
【问题描述】:

我有以下例子:

struct Wrapper
{
    virtual ~Wrapper()
    {
    }

    template <typename U>
    WrapperT<U> * clone()
    {
        return new WrapperT<U>(value); //will not work, because value is not known here
    }
};

template <typename T>
struct WrapperT : Wrapper
{
    explicit WrapperT(T v)
    {
        value = v;
    }

    T value;
};

我想要这样的东西:

Wrapper *t = new WrapperT<int>(1);
WrapperT<double> *t2 = t->clone<double>();

我知道虚拟模板不可用。有什么想法吗?

【问题讨论】:

  • 当有人在下一行执行t-&gt;clone&lt;foo*&gt;() 时,您希望发生什么? (其中foo 是完全不相关的类型)
  • 转换构造函数template&lt;typename U&gt; explicit WrapperT(const WrapperT&lt;U&gt;&amp;);怎么样?
  • @jrok:那个构造函数不会知道真正的类型。他想从指向基类的指针转换为派生类型。

标签: c++ templates virtual


【解决方案1】:

一种可能的方法是定义访问者模式,但如果您想支持许多不同的包装类型(即如果它不仅仅是一个小子集),那么实现访问者的成本可能会很大。

您会遇到的另一个问题是转换将(必须)动态分派,因此它们可能在运行时失败,您必须提供机制来检测并采取行动(想到例外)。没什么可怕的......

【讨论】:

  • 我觉得这种模式不适合我的应用程序。我想转换编译器支持的所有可能类型。
  • @SteffenRoeber:问题是当您传递的元素是基本类型时,您会丢失类型信息。为了能够恢复该类型信息,您需要在运行时使用动态分派,但完全 通用 解决方案需要模板和静态分派(即让编译器生成您需要的代码段)。您将需要找到不同的设计。
【解决方案2】:

我提出的解决方案是使用“中性类型”来动态(正如 David Rodríguez - dribeas 所说)进行类型转换。

优势:

  • 解决方案是通用的:使用新类型时不需要做任何特别的事情。

作为缺点

  • 不利于性能。
  • 需要定义插入和提取流运算符。

代码:

struct Wrapper
{
    // get the "neutral type" value
    virtual string getValue() const = 0;

    template <typename U> Wrapper* clone() const;
};

template <typename T>
struct WrapperT: Wrapper
{
    explicit WrapperT(T v):  value(v)
    {
    }

    virtual string getValue() const 
    {
        // use streams to conversion to neutral value, but 
        // other better method would be suitable
        ostringstream   strm;
        strm << value;
        return strm.str();
    }

    T value;
};

template <typename U> Wrapper* Wrapper::clone() const {
    U   value;
    istringstream   strm(getValue());
    strm >> value;

    return new WrapperT<U>(value);
}

编辑:

为了获得更好的性能解决方案,如果只使用数字类型,我们可以将string 更改为long double 为“中性类型”:

template <typename T>
double long WrapperT<T>::getValue() const 
{
    return value;
}

template <typename U> Wrapper* Wrapper::clone() const {
    return new WrapperT<U>(getValue());
}

我们是否希望在仅使用整数类型时避免整数到浮点的转换?在这种情况下,解决方案会稍微复杂一些:

  • 创建两个getValue() 虚函数,一个用于整数,另一个用于浮点,
  • clone() 函数中根据U 模板参数类型(目标类型)选择所需的getValue() 函数。

【讨论】:

  • 我需要一个高性能的解决方案。我认为流媒体是别无选择的。
  • 我读过一些关于蹦床功能的文章。但他们是否适合这里我不知道。
  • @SteffenRoeber:您可以创建自己的转换函数。如果您一直使用数字类型,您可以转换为浮点类型(doublelong double)作为中性类型。
  • 我#m不仅使用数字。怎么会有这样的转换函数?
  • @SteffenRoeber:还有哪些类型?聚合、枚举、指针……所有这些?中性类型必须类似于一个类,可以作为您想要支持的每种类型的构造函数,以及您想要支持的每种类型的转换函数。
猜你喜欢
  • 2020-07-08
  • 2023-04-01
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 2017-01-13
  • 2020-06-07
  • 2015-06-27
相关资源
最近更新 更多