Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;模板函数实例化代码大小_C++_Templates_Optimization_Size - Fatal编程技术网

C++ C++;模板函数实例化代码大小

C++ C++;模板函数实例化代码大小,c++,templates,optimization,size,C++,Templates,Optimization,Size,我试图减少模板函数实例化的数量,但遇到了一个障碍 假设我们有以下类(我知道它没有优化:这是为了说明问题而做的): //类no\u inherit的实现方式与类base(如下)相同。 //这样做是为了说明我所看到的问题。 模板 类no_继承 { 私人: T m_数据[大小]; 常数大小; 公众: no_inherit():m_size(size){} T&T操作员[](尺寸i) {返回m_数据[i];} 内联大小\u t size()常量 {返回m_size;} }; 以下功能: templa

我试图减少模板函数实例化的数量,但遇到了一个障碍

假设我们有以下类(我知道它没有优化:这是为了说明问题而做的):

//类no\u inherit的实现方式与类base(如下)相同。
//这样做是为了说明我所看到的问题。
模板
类no_继承
{
私人:
T m_数据[大小];
常数大小;
公众:
no_inherit():m_size(size){}
T&T操作员[](尺寸i)
{返回m_数据[i];}
内联大小\u t size()常量
{返回m_size;}
}; 
以下功能:

template<typename T>
void huge_func(T& v)
{
    //..do lots of stuff with v.  For example

    for(size_t i = 0; i < v.size(); ++i)
        v[i] = v[i] + i;

    //...do lots more with v
}
void huge_func(base<int>& v);
模板
无效巨大功能(T&v)
{
//…用v做很多事情。例如
对于(大小i=0;i
以及以下代码:

int main()
{
    no_inherit<int, 4> v1;
    no_inherit<int, 2> v2;

    huge_func(v1);
    huge_func(v2);
}
intmain()
{
no_继承v1;
没有"v2",;
巨函数(v1);
巨函数(v2);
}
巨大的_func()将被实例化两次:

void huge_func(no_inherit<int, 4>& v);
void huge_func(no_inherit<int, 2>& v);
void巨型函数(无继承&v);
无效巨大函数(无继承&v);
由于巨_func()非常庞大,因此我尝试通过使用其中一个模板参数并通过创建以下类层次结构将其转换为动态参数来减少实例化计数:

//Base class only has 1 template parameter.
template<typename T>
class base
{
private:
    T *m_data;  
    const size_t m_size; //hold child's templated size parameter.

protected:
    inline base(T* data, size_t size): m_data(data), m_size(size){}

public:
    T& operator[](size_t i)
    {return m_data[i];}

    inline size_t size() const
    {return m_size;}
};

//Child class has two template parameters
template<typename T, size_t SIZE>
class inherit: public base<T>
{
private:    
    T m_data[SIZE];

public:
    //Pass template parameter to base class
    inherit() : base<T>(m_data, SIZE){}
};
//基类只有一个模板参数。
模板
阶级基础
{
私人:
T*m_数据;
const size\u t m\u size;//保留子级的模板大小参数。
受保护的:
内联基(T*数据,大小:m_数据(数据),m_大小(大小){}
公众:
T&T操作员[](尺寸i)
{返回m_数据[i];}
内联大小\u t size()常量
{返回m_size;}
};
//子类有两个模板参数
模板
类继承:公共基
{
私人:
T m_数据[大小];
公众:
//将模板参数传递给基类
inherit():基(m_数据,大小){}
};
我调用maging_func()如下:

int main()
{
    inherit<int, 4> v1;
    inherit<int, 2> v2;

    //make sure only one instantiation of huge_func() is made
    //by using the same type.
    base<int> &v1b = v1;
    base<int> &v2b = v2;

    huge_func(v1b); 
    huge_func(v2b);
}
intmain()
{
继承v1;
继承v2;
//确保只进行了一次大型函数的实例化
//通过使用相同的类型。
基本&v1b=v1;
基础&v2b=v2;
巨函数(v1b);
巨函数(v2b);
}
这只会实例化一个巨大的函数:

template<typename T>
void huge_func(T& v)
{
    //..do lots of stuff with v.  For example

    for(size_t i = 0; i < v.size(); ++i)
        v[i] = v[i] + i;

    //...do lots more with v
}
void huge_func(base<int>& v);
void巨大的函数(基本&v);
这样会减少代码大小

但是,唉!使用类层次结构时,代码大小会增加。这怎么可能

更奇怪的是,如果我有以下代码

int main()
{
    inherit<int, 4> v1;
    inherit<int, 2> v2;

    huge_func(v1);
    huge_func(v2);
}
intmain()
{
继承v1;
继承v2;
巨函数(v1);
巨函数(v2);
}
代码大小与调用巨型函数(v1b)和巨型函数(v2b)相同


编译器在做什么?

首先,如果
maging\u func
确实是“巨大的”,您可能会从将其拆分为几个可重用的较小函数中获益

除此之外,您还可以将其模板化:

template<typename T, int SIZE> void huge_func(no_inherit<T, SIZE>& v)
{
    // function implementation goes here
}
模板无效巨大函数(无继承(&v)
{
//函数实现在这里进行
}

然后您将实现它一次,并维护您的平面类结构。

您是否实际查看了编译器生成的代码?换句话说,您是否确定第一个示例为您提供了两个不同的函数?是的。在调试版本中,映射文件有两个不同的函数。不幸的是,启用O3后,映射文件不包含任何信息,因此这是一个谜,但我只能假设这两个版本仍然以某种方式存在,形状或形式。对,这可能是编译器在O3中内联代码的情况,因此您可以得到更多的代码,但代码相同。如果您想要更小的代码,请尝试使用-Os。与-Os相同的代码大小问题。事实上,我已经尝试了所有的优化(O0、O1、O2、O3和OS),结果都是一样的(层次结构会生成更大的代码)。谢谢你的建议。虽然此解决方案可以部分解决问题,但在大型函数()应接受任何类型(例如,提供[]运算符)的情况下,它不能很好地工作。换句话说,如果巨函数()要处理数组和类,我不能强制巨函数()使用no_inherit类。另外,使用您提供的函数签名,在向函数传递两个不同的no_继承类型时,suggest_func()是否仍会实例化两次?回答上一个问题,首先:是。每次用一组新参数调用它时,基本上都是用一个新类型重载它。如果您担心函数被编译两次,那么您只能通过尝试将其转换回已实例化的对象来绕过基本派生方法中的问题。您可以通过不将
magig_func
设置为模板(例如,只将其参数设置为
void*
,或允许其使用迭代器等)来完成相同的任务,这样可以在编译的代码中创建函数的一个实例,并保持类结构平坦。此外,要回答您关于使用基本派生方法时代码大小如何增加的问题:使用继承会带来开销。它生成的汇编代码必须进行大量维护才能维护vtables。使用base调用big_func()不就是这样吗:将数据转换为已实例化的类型?不幸的是,void*在这种情况下不行(如果我可以的话,那就太好了)。至于迭代器,它们与使用基类/继承类有何不同(我能看到迭代器工作的唯一方法是通过使[]操作符虚拟来提供额外级别的间接寻址)。但是我的类没有虚拟例程,因此没有要编译的vtables。