【问题标题】:Does C++ treat an instantiated template class any differently from a non-templated type?C++ 对待实例化的模板类与非模板类型有什么不同吗?
【发布时间】:2021-04-02 11:21:12
【问题描述】:

使用虚函数时,对基类和所有派生类都使用单个类模板通常很方便。我的问题是:C++ 编译器以这种方式定义的类与没有模板定义的相同类有什么不同吗?

以下是使用模板创建的一些类的示例:


template <typename T=void> struct Adder;

template <> struct Adder <void>
{
    virtual double add(double a, double b)
    {
        return (a+b);
    }
};

template <typename T> struct Adder : Adder <void>
{
    virtual double add(double a, double b)
    {
        return ((T)a+(T)b);
    }
};

    
using AdderBase   = Adder <void>;
using AdderInt    = Adder <int>;
using AdderFloat  = Adder <float>;
using AdderDouble = Adder <double>;

int main(int argc, char* argv[])
{
    AdderBase* addI = new AdderInt;
    AdderBase* addF = new AdderFloat;
    AdderBase* addD = new AdderDouble;

    printf("addI = %18.1f\n", addI->add(11111111111111111.0, 1.0));
    printf("addF = %18.1f\n", addF->add(11111111111111111.0, 1.0));
    printf("addD = %18.1f\n", addD->add(11111111111111111.0, 1.0));
}

下面是一个在没有模板的情况下创建的具有相同功能的类的示例:


struct AdderBase
{
    virtual double add(double a, double b)
    {
        return (a+b);
    }
};

struct AdderInt : AdderBase
{
    virtual double add(double a, double b)
    {
        return ((int)a+(int)b);
    }
};

struct AdderFloat : AdderBase
{
    virtual double add(double a, double b)
    {
        return ((float)a+(float)b);
    }
};

struct AdderDouble : AdderBase
{
    virtual double add(double a, double b)
    {
        return ((double)a+(double)b);
    }
};

当以这两种不同的方式定义类 AdderBase、AdderInt、AdderFloat 或 AdderDouble 时,编译器是否会以不同的方式处理它们?

当类用作重载函数中的参数时,重载解析的不同顺序可能是一个不同的示例。

【问题讨论】:

  • “以这种方式定义的类有什么不同” 可能不是。但是为什么你需要基类成为模板的特化呢?有一个单独的类不是更易读吗?
  • "使用虚函数时,基类和所有派生类都使用单个类模板通常很方便" 为什么?这有什么“方便”的?
  • "对基类和所有派生类都使用一个类模板" -- 当你对这两个类使用相同的模板name基类和派生类,我不会将您的代码描述为使用单个类模板。从技术上讲确实如此,但仍有两个定义需要维护——一个用于Adder &lt;void&gt; 专业化,一个用于一般情况。这与对基类使用非模板并没有“感觉”不同。
  • 您能否举例说明以不同方式处理类可能需要什么?你担心的是什么样的事情? (我可能期望某种模板语法错误,但 using 别名应该可以防止这种情况发生。)

标签: c++ templates types virtual


【解决方案1】:

简短的回答是否定的。

特别是,当您使用(例如)AdderFloat 的任一实现时,我希望任何合理的编译器都能生成相同的代码。事实上,甚至在代码生成器开始查看代码之前,两者都在努力简化为相同的中间表示。

在某些情况下,您可以从模板中获取不同的代码,但最常见的情况是,您知道某些特定类型有一个快捷方式,然后编写一个专门化来让编译器利用该特定类型的快捷方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    相关资源
    最近更新 更多