class中static const int的使用

传统认识

我们都知道,对于class 中static const int 的变量,可以在类中进行初始化,并省去外部的定义,向下面的这种方式;此时,编译,执行均是正确的。

class test
{
 static const int tmp_int = 1;
 public:
 void print() {
    printf("%d", tmp_int);
    // foo(tmp_int);
    //foo1(tmp_int);
    //std::list i_list;
    //i_list.push_back(tmp_int);
  }
};

意料之外

  1. 在函数模板中使用tmp_int
    但是,当对tmp_int采用一些特殊用法时,程序链接过程中则会出现错误,代码如下:
template<class T>
void foo(const T &a)
{
  printf("%d", a);
}
void foo1(int a)
    {
      printf("%d", a);
    }
class test
{
  static const int tmp_int = 1;
public:
  void print() {
    printf("%d", tmp_int);
    foo(tmp_int);// 此处会报找到不tmp_int的定义
    foo1(tmp_int);//正常通过编译连接
  }
};
  1. 作为一个参数传递给需要引用类型实参的函数
void foo1(int &a)
    {
      printf("%d", a);
    }
class test
{
  static const int tmp_int = 1;
public:
  void print() {
    printf("%d", tmp_int);
    // foo(tmp_int);
    foo1(tmp_int);//此处报错,同上
    std::list<int> i_list;
    //i_list.push_back(tmp_int);//此处同样会报错,现象和原因同上
  }
};

情理之中

上诉现象的主要原因可以通过两点进行概括:1.在class中对tmp_int进行初始化,并不会对tmp_int真正的分配地址;2.无论是模板还是引用,都需要地址。
查看tmp_int的符号表,只在类中进行初始化,得到如下结果:

tingshuai@yantingshuaideMacBook-Air ~$ nm test.o
0000000000000070 S __Z3fooIiEvRKT_
0000000000000030 S __ZN4test5printEv
                 U __ZN4test7tmp_intE
0000000000000000 T _main
                 U _printf

在类外加上tmp_int的定义,结果如下:

tingshuai@yantingshuaideMacBook-Air ~$ nm test.o
0000000000000070 S __Z3fooIiEvRKT_
0000000000000030 S __ZN4test5printEv
000000000000009c S __ZN4test7tmp_intE
0000000000000000 T _main
                 U _printf

谍影重重

  1. 编译器对class中的static const int 如何处理的?为什么会没有地址
  2. 模板编译时需要实例化(是在编译时?需要进一步确定),实例化需要参数的地址来获取变量类型?那为何当为函数模板赋值一直常量时可以获取类型信息,而tmp_int不可以?
template<class T>
void foo(const T &a)
{
  printf("%d", a);
}
void foo1(int &a)
    {
      printf("%d", a);
    }
class test
{
  static const int tmp_int = 1;
public:
  void print() {
    printf("%d", tmp_int);
    foo(3);//可以通过编译连接,执行结果正确
    // foo1(3);
    std::list<int> i_list;
    //i_list.push_back(tmp_int);//tmp_int报错,传递常量则没有问题
  }
};

参考

https://bytes.com/topic/c/answers/850988-const-static-member
http://stackoverflow.com/questions/5391973/undefined-reference-to-static-const-int
http://www.cplusplus.com/forum/general/36478/

刨根问底

  1. 通过观察汇编可知,对于模板的代码是在编译阶段生成的(其实这是想当然的事情,难道在程序的执行过程中能生成代码,只能对自己以前的理解呵呵了);只不过是当模板函数或模板类被真正调用时,才会为其生成真正的代码段;如下面的代码
template<class T>
void foo(const T &a)
{

  printf("%d", a);
}

int main(int argc, char *argv[])
{
  foo(3);//第一次调用目标函数
  double d = 1.245;
  foo(d);//第二次调用
  return 0;
}

其汇编如下:

void foo(const T &a)
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
{

  printf("%d", a);
   c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  10:   8b 00                   mov    (%rax),%eax
  12:   89 c6                   mov    %eax,%esi
  14:   bf 00 00 00 00          mov    $0x0,%edi
  19:   b8 00 00 00 00          mov    $0x0,%eax
  1e:   e8 00 00 00 00          callq  23 <_Z3fooIiEvRKT_+0x23>
}
  23:   c9                      leaveq
  24:   c3                      retq

Disassembly of section .text._Z3fooIdEvRKT_:

0000000000000000 <_Z3fooIdEvRKT_>:
template
void foo(const T &a)
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
{

  printf("%d", a);
   c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  10:   f2 0f 10 00             movsd  (%rax),%xmm0
  14:   bf 00 00 00 00          mov    $0x0,%edi
  19:   b8 01 00 00 00          mov    $0x1,%eax
  1e:   e8 00 00 00 00          callq  23 <_Z3fooIdEvRKT_+0x23>
}
  23:   c9                      leaveq
  24:   c3                      retq

显而易见,生成了两个模板函数foo的实例化

你可能感兴趣的:(C++)