首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

【longshanks请进】关于您在小弟我帖子中的inline回复(由于结贴时候么没看到)

2012-04-05 
【longshanks请进】关于您在我帖子中的inline回复(由于结贴时候么没看到)是这样的,函数inline之后,并且编译

【longshanks请进】关于您在我帖子中的inline回复(由于结贴时候么没看到)
是这样的,函数inline之后,并且编译器允许inline,那么,函数会整个地在调用位置就地展开。就仿佛没有调用函数一样。相比标准函数的调用,inline省去了函数调用时的栈操作,包括参数压栈、寄存器压栈、栈清理等等。并且,由于函数代码就地展开,编译器在优化时可以将inline函数代码和调用方代码作为一个整体考虑,进一步加以优化。这一点标准函数是做不到的。
需要强调的是,inline不是强制的。某些编译器可能会不执行inline。但现在主流的编译器,如g++、vc、bcb等等都积极地执行inline。即便如此,inline并非总是执行的,比如递归的函数,编译器就拒绝inline,因为这种inline是做不到的。
编译器对inline的支持如何,需要参考相关文档,或者做些实验。而且,通常在debug状态下,inline是不做的,只有release编译,才会执行。
所有类型的函数都可以标记成inline,包括全局函数、成员函数、static函数。对于直接定义在class或struct中的成员函数,默认inline。如果定义在class/struct外的,则必须要通过inline关键字指定:
class   A
{
void   f1()   {...}   //inline
void   f2();
inline   void   f3();
};
void   A::f2()   {...}   //非inline
inline   void   f3()   {...}   //inline
最后,inline有一个有趣的现象。考虑如下函数:
int   a[100];
inline   void   fill_a(int   v)   {
      if(v==0)
            return;
      a[v]=v*10;
      fill_a(v-1);
}
fill_a(9);//希望inline展开
尽管使用了inline关键字,但编译器是不会inline的。但是,inline还是可以做到的:
template <int   n>
struct   fill_a
{
        void   operator()()   {
              a[n]=n*10;
              fill_a <n-1> ()();       //递归
        }
}
template <>
struct   fill_a <0>
{
        void   operator()()   {
              a[0]=0;
        }
}
fill_a <9> ()();
此时,fill_a <9> ()();编译后(优化打开)的代码可能是这样的(伪码):
a[9]=90;
a[8]=80;
...
a[0]=0;
这样,便实现了递归的inline。


=================================


很抱歉啊,在没看到您的回复之后我就已经结贴了,新在重新拿出来。请教几个小问题。

上面的代码我还真看不懂啊。为什么操作符后面带两个()()?还有想要看懂这样的代码需要参考什么资料啊。

template <int   n>
struct   fill_a
{
        void   operator()()   {
              a[n]=n*10;
              fill_a <n-1> ()();       //递归
        }
}
这个我懂。
可是下面这个:
template <>
struct   fill_a <0>
{
        void   operator()()   {
              a[0]=0;
        }
}
就不懂了。它是函数还是类?

[解决办法]
template <>
struct fill_a <0>
{
void operator()() {
a[0]=0;
}
}
=======================
这个是类.
void operator()()是对函数调用操作符 operator()的重载.一个类重载了operator()
后, 其对象就可以象函数那样调用了. STL中的防函数, boost中的function等等都用
到这个特性.

fill_a <0> filla;
filla(); // 调用operator(), 看起来与一个函数调用没有区别.

上面的operator()重裁不带参数, 返回null.
假如有另一个重载如int operator()(int a, int b), 你就可以传参数
和接收返回值了.
int result = filla(a, b)
.................


[解决办法]
【Ref】

函数对象概述
关 键 词:对象
阅读提示:函数对象是比函数更加通用的概念,因为函数对象可以定义跨越多次调用的可持久的部分(类似静态局部变量),同时又能够从对象的外面进行初始化和检查(和静态局部变量不同)。
顾名思义,就是在某种方式上表现得象一个函数的对象。典型地,它是指一个类的实例,这个类定义了应用操作符operator()。

函数对象是比函数更加通用的概念,因为函数对象可以定义跨越多次调用的可持久的部分(类似静态局部变量),同时又能够从对象的外面进行初始化和检查(和静态局部变量不同)。例如:



class Sum {

 int val;

 public:

Sum(int i) :val(i) { }

operator int() const { return val; } // 取得值

int operator()(int i) { return val+=i; } // 应用

};

void f(vector v)

{

 Sum s = 0; // initial value 0

 s = for_each(v.begin(), v.end(), s); // 求所有元素的和

 cout < < "the sum is " < < s < < "\n ";

 //或者甚至:

 cout < < "the sum is " < < for_each(v.begin(), v.end(), Sum(0)) < < "\n ";

}

注意一个拥有应用操作符的函数对象可以被完美地内联化(inline),因为它没有涉及到任何指针,后者可能导致拒绝优化。与之形成对比的是,现有的优化器几乎不能(或者完全不能?)将一个通过函数指针的调用内联化。

在标准库中,函数对象被广泛地使用以获得弹性。
[解决办法]
啊,大家手脚真快啊!lz发帖的时候我正在食堂里嚼鸡丁呢:)。这么一会儿,都把问题解决了。关于那两个(),ls说的都很完美了,我就不再画蛇添足了。
至于这个:
template <>
struct fill_a <0>
{
void operator()() {
a[0]=0;
}
}
它既不是函数,也不是类。是模板,而且是模板fill_a的特化。意思是:fill_a是针对模板参数n取值范围(int)内所有数值都成立的模板。但有一个例外,那就是当n为0的时候,必须做另外一种计算。模板的特化,就是为了描述这种例外的情况。这个特化模板告诉编译器:如果模板实例化时的模板参数是0,那么就用这个特化的版本。否则,就得使用前面的那个没有特化的fill_a(没有特化的那个版本称为基础模板)。
因为在基础模板中的operator()中执行了递归,那么必须要有一个结束递归的条件。而这个特化的版本便是递归的结束条件,即当模板实参是0的时候,不再递归。这是模板元编程所使用的一种基本手法。用以实现循环。而模板的特化就实现了分支的作用,相当于if...else...或switch。
[解决办法]
没错。而且不但能用类对象作为模板参数,还可以用前面的类型参数作为后面的非类型参数的类型:
template <class T, T i> void f(T t)
{...}
象int n这种模板参数叫做非类型模板参数,而象typename T或class T相应的称为类型模板参数。还有一种就是模板模板参数:
template <typename <typename T> class A>
class X
{
A <int> aa;
};
非类型模板参数的类型有一些限制,下面文字摘自C++标准:
14.1.4
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
— integral or enumeration type,
— pointer to object or pointer to function,
— reference to object or reference to function,
— pointer to member.
14.1.7
A non-type template-parameter shall not be declared to have floating point, class, or void type. [Example:
template <double d> class X; // error
template <double* pd> class Y; // OK
template <double& rd> class Z; // OK
14.1.8
A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type
“pointer to T” or “pointer to function returning T”, respectively. [Example:
template <int *a> struct R { /* ... */ };
template <int b[5]> struct S { /* ... */ };
int p;
R <&p> w; // OK
S <&p> x; // OK due to parameter adjustment
int v[5];
R <v> y; // OK due to implicit argument conversion
S <v> z; // OK due to both adjustment and conversion
—end example]
更多的关于模板的内容,可以参考《C++ Template》一书。

热点排行