• C++根据头文件自动生成实现文件框架(支持模版)


      以前写了一个,也贴出来了不过对模版支持不好,不带模版的函数和类成员函数还是支持的。

       

       最近写模版类的头文件,而模版类的话如果不想inline在外部实现的化,书写起来格式很麻烦。尤其是如果返回变量的类型是在类内部typedef的类型。

      所以对以前的程序修改了以下,还是利用Python正则表示生成对应的实现文件,对于模版类其实也可以生产.cc文件的将函数的实现写在.cc文件中,

      如在MeshT.h文件的最后include的实现文件MeshT.cc就可以了(Openmesh就是这么做的,下面有例子),

      这样避免代码都写在.h中比较乱,而且头文件太长。

      嗯,现在的h2cc.py基本能完成要求,可能有些特殊情况会出问题,待验证,另外代码有多个地方重复的地方待整理。

          下一步要做的

      1.进一步测试对各种情况正确无误,包括更复杂的模版测试,

          2.当前完全按照格式处理,不考虑语义理解,所以对于SGI STL源代码那样头文件中把函数返回变量单独写一行的无法处理。这个以后有好的办法再处理。

           (感觉做编译器的完全能写个.h到.cc的自动转换工具为啥我搜不到呢,还得自己写....肯定不如人家的精确)

          3. 当前如果存在生成文件了已经,比如用户开始生成了.cc然后又在.h中增加方法,再次生成.cc的时候我会将新的方法统一写在原来.cc文件的最后,具体合适

              的位置用户再改动。 下一步考虑自动将新的方法插入到原来.cc文件的合适位置,不过用户如果改动如函数格式,nameapce名称,新添加namespace等等肯定会带来问题

              那个用户自己处理吧(注意这里的.cc文件都是按照h2cc.py生成) 

          4.像java或者python那样,将所有的代码都写到一起,即不存在头文件的写法,这样代码写起来更方便。对于C++代码可以全部写到.h中。然后调用转换

              工具,自动生成.cc文件,将所有没有声明inline的函数并且实现代码长度超过n行的(如10行)自动在.h中转换为声明格式,在.cc中写成实现格式

              并把实现代码拷贝过去,

              可以用户紧挨函数在上面一行开头加注释如//*标明下面的函数不做转换处理在.h中inline。

              个人觉得这样还是能提高写程序的效率的,不知道现在有没有现成的转换工具。

           5.要做上面的工作需要对代码修改,当前的代码可扩充性太差....,扩展功能麻烦,首先把各个重复的地方提前出来统一处理。如去掉=的模式。

              试图写子函数,但是问题是我需要对每一行代码做太多的情形分析,这样while循环太长了,又不好分子程序,

              尤其是 python不支持类似c++的引用,写子函数修改输入变量如输入行号i并在子函数中修改,用Python还得返回i才行,别扭:( 

              嗯,最后决定暂时就这样了,程序不改了,当前的做法对于{}的处理采用统一忽略的做法包括类似if abc() {}的处理,修改实现其它的功能比较麻烦。。。 

    //h2cc.py

       1 #!/usr/local/bin/python3.1 

      2 #file    h2cc.py
      3 #author  pku_goldenlock@qq.com
      4 #date    2009-10-23 18:19:38.970028
      5 
      6 #.h convert to .cpp framework
      7 #注意!!
      8 #1. 我们假定你的.h代码书写正确 当前不做异常,错误处理
      9 #2. 函数的返回类型如 int 与 与函数名称要写到一行,否则会有问题,因为不太好判断函数名称.
     10 #3. 如果已经存在要生成的文件,会只写入你在.h中新加入的函数,
     11 #   但是注意原来已经存在的实现文件也应该是用h2cc.py生成的,因为我不是按语意判断,只是按照格式判断
     12 #   新写的实现函数框架,会附加到原来的生成文件最后面,需要自己调整到需要的位置,尤其是有namespace的时候
     13 #   TODO  新写的函数直接放到原来生成文件中适当的位置
     14 #4. 在生成的实现文件中,可能会把返回值单独一行,取决于行的长度,过长则分行
     15 #5. 如果template模板写成多行,确保最后一行只有一个单独的>
     16 #   template <
     17 #     typename T = char,
     18 #     template<typename> class _Decoder = HuffDecoder<int> #pattern like this might cause error 
     19 #   >
     20 
     21 
     22 #在某行发现) ; 之后,删除该行;之后的内容,该行开始的空白去掉
     23 #改为 \n\{\n\}
     24 # virtual = 0 对于纯虚函数也生成实体,如不需要自己去掉.  TODO 用户选项
     25 #TODO 允许向SGI STL源代码那样,将返回值单独一行,在函数名称上面,不过似乎比较困难,因为当前
     26 #我的程序基本按照(){};template class typdef define // /* */识别这些字符的,仅仅考虑格式
     27 #不考虑语意如果返回值
     28 #单独一行,如何判断什么样的是返回值类型呢?比较麻烦.比如还要区分仅仅挨着占两行的两个函数声明.
     29 
     30 #最常用的pattern
     31 #查找如下 )  ;   或者 ) const ;  但是不包括纯虚函数
     32 #()z中如找到     ;  //从队尾删除
     33 #开始的空白要找到并删除,
     34 #pattern = re.compile(r"([\s]*?).*[)](?!\s*=\s*0).*(;.*)\n$")
     35 
     36 #class A : public 读出A未解决  done
     37 #template                      done 支持模板类,模板函数,带有默认参数的模板,模板类中的模板函数,特化和偏特化
     38 #                                   TODO  更复杂的情况可能有问题,比如模板类中嵌套模板类
     39 #vitrual = 0                   done
     40 #支持 const                    done
     41 #宏   DFDFDFEE(ABC);          done
     42 #把注释拷贝                    done
     43 #已经有.cpp了  仅仅加新的接口的实现 partly done  
     44 #忽略返回类型,返回类型不能重载
     45 #operator   done
     46 
     47 import sys,re,getopt
     48 
     49 def usage():
     50     """ 
     51         Run the program like this
     52         
     53         ./h2cc.py abc.h ok.cc
     54         It will read abc.h and append the fuctions 
     55         to be implemented to ok.cc
     56         
     57         or 
     58            ./h2cc.py abc.h         #will create abc.cc
     59            ./h2cc.py abc.h cpp     #will create abc.cpp
     60         """
     61 pattern_comment = re.compile(r'^\s*//')
     62 
     63 #传入一个打开的文件(我们要生成的或者已经存在要分析处理)的handle,如abc.cc
     64 #调用该函数者负责关闭该文件,该函数只负责处理
     65 func_list_exist = []
     66 def AnalyzeOutputFile(file_handle):
     67     print('Analyze output file right now ,the reslt of existing functions is below\n')
     68     file_handle.seek(0,0)
     69     m = file_handle.readlines()
     70     i = 0
     71     #---------------------------------------------------逐行处理
     72     while (i < len(m)):
     73         line = m[i]
     74         #---------------------判断是注释则略过  re.search(r'^s*$',line) 空行判断
     75         if re.search(r'^s*$',line) or pattern_comment.search(line): #null line or comment using //
     76             i += 1
     77             continue
     78         if re.search('^\s*/[*]', line):                             #comment using /*  
     79             while (not re.search('[*]/\s*$',line)):                 # */
     80                 i += 1
     81                 line = m[i]
     82             i += 1
     83             continue
     84         #-------------------------find exists functions
     85         find1 = re.search('[(]',line) 
     86         find2 = re.search('[)]',line)
     87         find3 = re.search('template',line)
     88         find4 = re.search('::',line)
     89         if ((find1 or find3 or find4) and (not find2)):
     90             i += 1
     91             line += m[i] 
     92             while (i < len(m) and (not re.search('[)]',line))):
     93                 i += 1
     94                 line += m[i]
     95         match = re.search('^.*\)',line,re.MULTILINE|re.DOTALL)
     96         if match:
     97             print(match.group())
     98             func_list_exist.append(match.group())
     99         i += 1
    100     print('Output file analze done!')
    101     print('There are already %d functions exit\n'%len(func_list_exist))
    102 
    103 #转化核心函数,当前比较乱,代码重复,一个循环中代码太长了 TODO 
    104 #基本实现就是按照栈处理名称,区分是否class域的函数,忽略.h中已经实现函数{}内部的内容
    105 def h2cc(input_file,output_file):
    106     """
    107         kernal function given a .h file
    108         convert to a .cc one with
    109         all the functions properly listed
    110         """
    111     print('The file you want to deal with is '+input_file + \
    112         '\n It is converted to ' + output_file)
    113   
    114     #----核心的函数匹配模式
    115     pattern = re.compile(r"""(^[\s]*)             #leading withe space,we will find and delete after
    116                              ([a-zA-Z~_]            # void int likely the first caracter v or i
    117                             .* 
    118                             [)]                   #we find )
    119                             #(?!\s*=\s*0)          #if we find = 0  which means pur virtual we will not match after
    120                             #(?=\s*=\s*0) 
    121                             (?!.*{)              # we do not want the case int abc() const { return 1;}
    122                             .*)
    123                             (;.*)                 #we want to find ; and after for we will replace these later
    124                             \n$
    125                             """,re.VERBOSE | re.MULTILINE | re.DOTALL)
    126     
    127     #----处理virtual,explicit,friend,static 
    128     pattern2 = re.compile(r'(virtual\s+|explicit\s+|friend\s+|static\s+)')   
    129     
    130     #----开头的空白
    131     leading_space_pattern = re.compile('(^[\s]*)[a-zA-Z~]')   
    132     
    133     #我们默认函数都会有 如 abc(  abc ( 这样的模式存在
    134     #但是operator 是个例外,类名要加在operaotr前面,而且不存在上面的模式
    135     #operator = ()     ClassName::operator = ()
    136     #pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*[(]|operator.*[(])')   
    137     #难道替换不是仅仅替换括号里面的 而是全部替换? 恩,大括号 必须的 然后用\1没有\0 
    138     pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*|operator.*)[(]'
    139 
    140     pattern_template = re.compile('^\s*template')
    141     #pattern_template_end = re.compile('^\s*>\s*$') #TODO why wrong?
    142     pattern_template_end = re.compile('>\s*$')
    143 
    144     pattern_namespace = re.compile(r'namespace.*{')       #判断该行是否是 namespace出现
    145     #p2 = re.compile(r'class\s*(.*?)\s*{|struct\s*(.*?)\s*{')  
    146     #.*? 最小匹配  是否class出现,并记录class 名称
    147     pattern_class = re.compile(r'^[\s]*(class|struct)\s+([a-zA-Z0-9_\-]+<?)(?!.*;)'
    148     #modify 09.6.6 可以处理classa a 和 { 不在同一行,但是如果class 后发现;不处理
    149     #class一定是行开始或者前面可有空白
    150 
    151     pattern_start = re.compile('{')
    152     pattern_end = re.compile('}')
    153     
    154     stack = []                      #----状态可能是normal_now(位于{}中间的时候),class_now,namespace_now
    155     stack_class = []                #----存储class name
    156     stack_template = []             #----存储template name
    157     stack_typedef = []              #----存储当前class 作用域下的所有typedef得到的名称,函数返回类型需要
    158     
    159     first_convert = True            #是否是第一次生成的实现文件
    160     
    161     #--------------------------------------文件处理
    162     try:                              #09.6.6 处理要转换生成的.cc 或 .cpp文件不存在的情况,添加读异常
    163         f_out = open(output_file,'r+')    #r+  可读写但要求文件已经存在
    164         print(output_file + ' exists already, we will anlyze it to find the existing functions to avoid adding twice')
    165         AnalyzeOutputFile(f_out)                         #对输出文件进行预处理分析
    166         first_convert = False
    167     except IOError:
    168         print(output_file + ' does not exist yet, we will create am empty ' + output_file)
    169         f_out = open(output_file,'a')     #追加打开,这里因为用了异常先判断了是否文件存在,所以也可以用 w
    170                                           #如果没有前面的判断只能用 a ,w 会自动删除前面已有的内容
    171     print('Below functions will be added\n')
    172     if first_convert:
    173         f_out.write('#include "' + input_file + '"\n\n')  #注意 如果out文件已存在 那么经过前面的分析处理 指针已经指向了文件尾部
    174      
    175     func_sum = 0
    176     #--------------------------------------------------核心处理循环,逐行处理输入.h文件
    177     with open(input_file,'r') as f:
    178         m = f.readlines()
    179         i = 0
    180         while i < len(m):
    181             line = m[i]
    182             #-------------------------------------------判断是注释则略过  re.search(r'^s*$',line) 空行判断
    183             if re.search(r'^s*$',line) or pattern_comment.search(line): #/n or comment using //
    184                 i += 1
    185                 continue
    186             if re.search('^\s*/[*]', line):              #comment using /*  
    187                 while (not re.search('[*]/\s*$',line)):  # */
    188                     i += 1
    189                     line = m[i]
    190                 i += 1
    191                 continue
    192             #---------------------------------------------判断是则define略过
    193             define_match = re.search(r'^\s*#define',line)
    194             if define_match:
    195                 while re.search(r'^\s*$',line) or re.search(r'\\\s*$', line):
    196                     i += 1
    197                     line = m[i]
    198                 i += 1
    199                 continue
    200             #-----------------------------------------------判断是否namespace
    201             match_namespace = pattern_namespace.search(line)
    202             if match_namespace:                                   #we face namespace
    203                 if first_convert:
    204                   f_out.write(line+'\n')
    205                 stack.append('namespace_now')
    206                 i += 1
    207                 continue
    208             #----------------------------------------------------判断并处理类里面的typedef
    209             if (len(stack) > 0 and stack[-1== 'class_now'):
    210                 pattern_typedef = re.compile(r'typedef\s+.*\s+(.*);')
    211                 match_typedef =  pattern_typedef.search(line)
    212                 if match_typedef:
    213                     stack_typedef.append(match_typedef.group(1))
    214             #----------------------------------------------------判断并处理模板情况  
    215             match_template = pattern_template.search(line)
    216             template_string = ''
    217             if match_template:
    218                 match_template_end = pattern_template_end.search(line)
    219                 template_string = line
    220                 while(not match_template_end):
    221                     i += 1
    222                     line = m[i]
    223                     template_string += line
    224                     match_template_end = pattern_template_end.search(line)
    225                 i += 1
    226                 line = m[i]
    227             #--------------------------------------------判断是否是class 或者遇到 { start
    228             match_class = pattern_class.search(line)  
    229             match_start = pattern_start.search(line)
    230 
    231             if match_class:                  #we face a class
    232                 stack_template.append(template_string)
    233                 stack.append('class_now')
    234                 class_name = match_class.group(2)   #TODO f2.group(1)如果为空则异常
    235                 #-----------模板类特化或者偏特化的情况 如 class A<u,Node<u> > 为了获得整个名称
    236                 if '<' in class_name:               
    237                     k = line.index('<')
    238                     fit = 1;
    239                     for l in range(k+1, len(line)):
    240                         if line[l] == '<':
    241                             fit += 1
    242                         if line[l] == '>':
    243                             fit -= 1
    244                         if (fit == 0):
    245                             break
    246                     class_name += line[k+1:l+1]
    247                 stack_class.append(class_name)
    248                 while not match_start:
    249                     i += 1
    250                     line = m[i]
    251                     match_start = pattern_start.search(line)
    252                 i += 1
    253                 continue
    254             #-------------------------------------------------判断是否是结束符号 }
    255             match_end = pattern_end.search(line)
    256             if match_start:
    257                 stack.append('normal_now')
    258             if match_end:
    259                 top_status = stack.pop()
    260                 if top_status == 'namespace_now':
    261                     if first_convert:
    262                       f_out.write(line+'\n')
    263                 elif top_status == 'class_now':
    264                     stack_class.pop()
    265                     stack_template.pop()
    266                     stack_typedef = []
    267             if match_start or match_end:
    268                 i += 1
    269                 continue
    270             #注意我判断是函数只是根据 我看到该行有) 然后 后面有;  important!!
    271             #------------------------------------------------就像忽略注释一样忽略normal_now状态下的行,因为那是在{}中间的实现
    272             if len(stack) >and stack[-1== 'normal_now'
    273                 i += 1
    274                 continue
    275             #---------------------------------------------------------下面我们该处理需要生成实体框架的函数了,
    276             #deal with
    277             #int abc(int a,
    278             #          int b)    #能够处理这种(与)不在同一行的情况
    279             find1 = re.search('[(]',line)
    280             if not find1:
    281                 i += 1
    282                 continue
    283             find2 = re.search('[)]',line)
    284             start_i = i
    285             if (find1 and (not find2)):
    286                 #space = leading_space_pattern.search(line).group(1)
    287                 space_match = leading_space_pattern.search(line)
    288                 i += 1
    289                 line2 = m[i]
    290                 if space_match:
    291                     line2 = re.sub('^'+space_match.group(1),'',line2)     
    292                     #注意sub会替换所有的匹配,这里我们只让它替换第一个,count=1,或者对于space 前面加^
    293                 line += line2
    294                 while (i < len(m) and (not re.search('[)]',line2))):
    295                     i += 1
    296                     line2 = m[i]
    297                     line2 = re.sub('^'+space_match.group(1),'',line2)
    298                     line += line2
    299 
    300             match_start = pattern_start.search(m[i])
    301             match_end = pattern_end.search(m[i])
    302             if (match_start):     # like  ) {  or ) {}    int the last line
    303               if not match_end:
    304                 stack.append('normal_now')
    305               i += 1
    306               continue
    307  
    308             #here we do the kernel sub  #--------------------------------如果找到,先进行了替换abc();->abc{}
    309             (line,match) = pattern.subn(r'\2 \n{\n\n}\n\n',line)       
    310             if (not match):   # like  abc()  not ; after 就是说{在函数名下面单独一行的情况
    311                 i += 1
    312                 continue
    313 
    314             #-------------------------------------------------------------OK,找到了函数,下面进行处理后输出
    315             if match:                           
    316                 friend_match = re.search('friend ',line)
    317                 line = pattern2.sub('',line)            #--------------------delete virtural explict friend!
    318                 func_name = ''
    319                 template_line = ''
    320                 if len(stack_class) > 0 and not friend_match :  #-----类成员函数class status if friend we will not add class name
    321                     x = ''
    322                     if (template_string != ''):                 #-----类中模板函数,多一个模板
    323                         template_string = re.sub(r'\s*template','template',template_string)
    324                         #template_string = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_string)
    325                         #------------------delete < class T = a, class U = A(3)> -> <class T, class U>
    326                         template_string = re.sub('\s*=.*>(\s*)$',r'>\1',template_string)  
    327                         template_string = re.sub(r'\s*=.*,',',',template_string)
    328                         template_string = re.sub(r'\s*=.*','',template_string)
    329                     if (stack_template[-1!= ''):
    330                         if not (re.search(r'<\s*>', stack_template[-1])): #----不是全特化!template<>
    331                             template_line = re.sub(r'^\s*template','template',stack_template[-1])
    332                             if not (re.search(r'<.*>', stack_class[-1])): #----不是偏特化!,like template<typename T> class A<T,int>
    333                                 #------for x we get like template<class T, typename U> -> <T,U>
    334                                 x = re.sub(r'template\s*<','<',template_line)    #remove template -> <class T, typename U>
    335                                 x = re.sub(r'\n','',x)                           #取消分行,合并成一行
    336                                 #去掉 = 及其后面的东西
    337                                 x = re.sub(r'\s*=.*,'',', x)
    338                                 x = re.sub(r'\s*=.*\>''>', x)
    339                                 x = x.rstrip()             #remove \n
    340                                 x = re.sub(r'(class|typename)\s+|(<class>|<typename>\s*class)','',x) #去掉class,typename ->  <T, U>
    341                                 x = re.sub(r'<\s+','<',x)
    342                                 x = re.sub(r'\s+>','>',x)
    343                                 x = re.sub(r'\s+,'',',x)
    344                                 x = re.sub(r',\s+''',x)  
    345                     line = re.sub(r'\s*=\s*0','',line)     #纯虚函数我们也给函数实现体,这里特别判断一下去掉 = 0
    346                     line = re.sub(r'\s*=.*,',',', line)  #去掉=后面的东西 foo(int a = cd(32));foo(int x =(3), int y= 4);
    347                     line = re.sub(r'\s*=.*\)',')', line)   #先去掉所有的(),最后去掉()),这两个步骤都需要不能颠倒
    348                     #---------如果函数较长,在void ABC::foo()  断开成两行 void ABC::\n foo()
    349                     temp_line = pattern_func_name.sub(stack_class[-1+ x + '::' + r'\1(',line)
    350                     if len(temp_line) > 60:
    351                         line = pattern_func_name.sub(stack_class[-1+ x + '::\n' + r'\1(',line)
    352                     else:
    353                         line = temp_line
    354                     #----------得到返回变量的类型 
    355                     return_type = re.search('^(\S+)', line).group(1)
    356                     if (return_type in stack_typedef):  #------对于返回值,需要指明是在该类中typedef指定的名称的情况
    357                         if (x == ''): #----全特化的情况特殊处理 
    358                             line = re.sub('^'+return_type+r'\s+', stack_class[-1]+'::'+return_type+'\\n', line)
    359                         else:
    360                             line = re.sub('^'+return_type+r'\s+''typename '+stack_class[-1]+'::'+return_type+'\\n', line)
    361                     #----------add template as the above if there is one
    362                     #template_line = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_line)
    363                     #------------------delete < class T = a, class U = A(3)> -> <class T, class U>
    364                     template_line = re.sub('\s*=.*>(\s*)$',r'>\1',template_line)
    365                     template_line = re.sub(r'\s*=.*,',',',template_line)
    366                     template_line = re.sub(r'\s*=.*','',template_line) #最后,不换行删除后面所有的
    367                     line = template_line + template_string +  line;        
    368                     func_name = re.search('^.*\)',line,re.MULTILINE|re.DOTALL).group()
    369                 else:                  #--------------------------------普通函数(非类成员函数)的情况!
    370                     stack_template.append(template_string)
    371                     if  (stack_template[-1!= ''):
    372                         template_line = re.sub(r'\s*template','template',stack_template[-1])
    373                         #template_line = re.sub(r'\s*=\s*[\'a-zA-Z0-9_\-\.]+', '', template_line)
    374                         #------------------delete < class T = a, class U = A(3)> -> <class T, class U>
    375                         template_line = re.sub('\s*=.*>(\s*)$',r'>\1',template_line) #代码重复,TODO以后整合 
    376                         template_line = re.sub(r'\s*=.*,',',',template_line)
    377                         template_line = re.sub(r'\s*=.*','',template_line)
    378                     line = re.sub(r'\s*=.*,'',', line)
    379                     line = re.sub(r'\s*=.*\)'')', line)
    380                     line = template_line + line
    381                     stack_template.pop()
    382                     func_name = re.search('^.*\)',line,re.MULTILINE|re.DOTALL).group()
    383                 #-------------------------------------------------------------------------加上上面的注释也拷贝过去
    384                 comment_line = ''                          
    385                 #假定函数的注释在函数声明的紧上面,把他们拷贝过去
    386                 #TODO 如果是模板函数,模板占多于1行注释没拷贝
    387                 k = start_i - 1    #one line befor this func start
    388                 if pattern_template.search(m[k]):
    389                     k -= 1
    390                 if re.search('[*]/\s*$',m[k]):
    391                     comment_line = m[k].lstrip()
    392                     while not re.search('^\s*/[*]',m[k]):
    393                         k -= 1
    394                         comment_line = m[k].lstrip() + comment_line 
    395                 else:    
    396                   for j in range(k,0,-1):
    397                       c_line = m[j]
    398                       if pattern_comment.search(c_line):
    399                           c_line = re.sub('\s*//','//',c_line)  #TODO use strtip is ok?
    400                           comment_line = c_line + comment_line
    401                       else:
    402                           break
    403                 line = comment_line + line  #------------------我们最终要输出的东东
    404                 #----------------------------------------------如果函数已经在实现文件中存在,不输出
    405                 if not(func_name in func_list_exist):
    406                     #if not first_convert and func_sum == 0:
    407                     #    f_out.write("//newly added functions, you may need to move them to the right position\n")
    408                     f_out.write(line)
    409                     func_sum += 1
    410                     print(func_name)
    411             i += 1  #-----------------------------------------------------------------------next line处理下一行
    412     #------------------------------loop done 处理结束 
    413     print('\nSucessfully converted,please see '+output_file)
    414     print('Added %d functions'%func_sum)
    415 
    416 
    417 #-----------------------------------------------------------user input
    418 def main(argv):                         
    419     try:                                
    420         opts, args = getopt.getopt(argv, "h", ["help"]) 
    421     except getopt.GetoptError:           
    422         print(usage.__doc__
    423         sys.exit(2)
    424 
    425     if len(opts) > 0:
    426         for o, a in opts: 
    427             if o in ("-h""--help"): 
    428                 print(usage.__doc__
    429                 sys.exit()
    430     elif len(args) > 0:
    431         input_file = args[0]
    432         if len(args) == 1 or args[1== 'cc':
    433             output_file = re.sub('.h*$','.cc',input_file)  # 默认转的是对应的.cc文件
    434         elif (args[1== 'cpp'):
    435             output_file = re.sub('.h*$','.cpp',input_file)
    436         else:
    437             output_file = args[1]
    438             
    439         h2cc(input_file,output_file)
    440     else:
    441         print(usage.__doc__)
    442         sys.exit()
    443 
    444 
    445 if __name__ == "__main__":
    446     main(sys.argv[1:])
    447 

    下面看一下常用的几种函数声明,其对应函数实现的写法,包括模版类函数,模版类中的模版函数等等。

       1 /*演示函数定义的格式,主要演示在模版类外面定义成员函数的写法*/

      2 #include <iostream>
      3 using namespace std;
      4 
      5 int abc(int x = 3int y = 4);
      6 
      7 template<typename T>
      8 struct HuffDecoder {
      9 
     10 };
     11 template <
     12   typename T = char,
     13   template<typename> class _Decoder = HuffDecoder
     14   >
     15 struct Hand{
     16   bool operator > (const Hand<T,_Decoder>& other);
     17   static void print();
     18 };
     19 
     20 template<typename T, template<typename> class _Decoder>
     21 void Hand<T, _Decoder>::print() 
     22 {
     23   cout << "this is hand" << endl;
     24 }
     25 
     26 template<typename T = char>
     27 class Foo {
     28   public:
     29     typedef T Node;
     30     typedef Hand<T> Handle;
     31     typedef int size;
     32 
     33     Handle foo(Node a);
     34 
     35     //Handle foo(Node a) {
     36     //  cout << "haha" << endl;
     37     //}
     38 
     39     //static Handle foo2(Node a = 'a') {
     40     //  cout << "haha" << endl;
     41     //}
     42     static Handle foo2(Node a = 'a');
     43 
     44     Hand<T> foo3();
     45 
     46     template <typename U>
     47     void swap(U x);
     48 
     49     //template <typename U>
     50     //class abc {
     51     //  public:
     52     //    static swap() 
     53     //};
     54 };
     55 
     56 template<typename T = char>
     57 class Derive : public Foo<T> 
     58 {
     59   public:
     60   typedef typename Foo<T>::size size; 
     61   static void print() {
     62     size l = 3333;
     63     cout << l << endl;
     64   }
     65 };
     66 template<>
     67 class Foo<int>
     68 {
     69   public:
     70     typedef int Node;
     71     typedef Hand<int> Handle;
     72     Handle foo(Node a);
     73     //Handle foo(Node a) {
     74     //  cout << "int foo" << endl;
     75     //}
     76     
     77 };
     78 
     79 template <typename T>
     80 class Foo<T*>
     81 {
     82   public:
     83     typedef Hand<int> Handle;
     84     typedef int Node;
     85     Handle foo(Node a);
     86 };
     87 
     88 template <typename T>
     89 typename Foo<T*>::Handle Foo<T*>::foo(Node a) {
     90   cout << "T * foo" << endl;
     91 }
     92 
     93 //template<>
     94 //typename Foo<int>::Handle Foo<int>::foo(Node a) 
     95 //{
     96 //  cout << "int foo" << endl;
     97 //}
     98 //
     99 Foo<int>::Handle Foo<int>::foo(Node a) 
    100 {
    101   cout << "int foo" << endl;
    102 }
    103 
    104 //Hand<int> Foo<int>::foo(Node a) 
    105 //{
    106 //  cout << "int foo" << endl;
    107 //}
    108 //
    109 template <typename T>
    110 void print(T x);
    111 
    112 template <typename T>
    113 void print(T x) 
    114 {
    115   cout << x << endl;
    116 }
    117 
    118 template<typename T>
    119 template<typename U>
    120 void Foo<T>::swap(U x) 
    121 {
    122   cout << "hehe" << endl;
    123 }
    124 
    125 template<typename T>
    126 typename Foo<T>::Handle Foo<T>::foo(Node a) 
    127 //Handle Foo<T>::foo(Node a)
    128 {
    129   size x = 23;
    130   cout << x << endl;
    131   cout << "haha" << endl;
    132 }
    133 
    134 template<typename T>
    135 typename Foo<T>::Handle Foo<T>::foo2(Node a) 
    136 {
    137   cout << "haha" << endl;
    138 }
    139 
    140 template<typename T>
    141 Hand<T> Foo<T>::foo3() 
    142 {
    143   cout << "haha" << endl;
    144 }
    145 
    146 
    147 int main(int argc, char *argv[])
    148 {
    149 
    150   Derive<>::print();
    151 
    152   Hand<int> hand;
    153   hand.print();
    154 
    155   Foo<>::foo2();
    156   Foo<> foo;
    157   foo.foo('a');
    158 
    159   foo.foo3();
    160   
    161   foo.swap(3);
    162   
    163   ::print(10);
    164 
    165   Foo<int> fooint;
    166   fooint.foo(4);
    167 
    168   Foo<int *> foopint;
    169   foopint.foo(4);
    170   
    171   return 0;
    172 }
    173 


     //用h2cc.py脚本生成的实现文件框架

      1 #include "test.h"

     2 
     3 int abc(int x, int y) 
     4 {
     5 
     6 }
     7 
     8 template <
     9   typename T,
    10   template<typename> class _Decoder
    11   >
    12 bool Hand<T, _Decoder>::
    13 operator > (const Hand<T,_Decoder>& other) 
    14 {
    15 
    16 }
    17 
    18 template <
    19   typename T,
    20   template<typename> class _Decoder
    21   >
    22 void Hand<T, _Decoder>::print() 
    23 {
    24 
    25 }
    26 
    27 template<typename T>
    28 typename Foo::Handle
    29 Foo<T>::foo(Node a) 
    30 {
    31 
    32 }
    33 
    34 //static Handle foo2(Node a = 'a') {
    35 //  cout << "haha" << endl;
    36 //}
    37 template<typename T>
    38 typename Foo::Handle
    39 Foo<T>::foo2(Node a) 
    40 {
    41 
    42 }
    43 
    44 template<typename T>
    45 Hand<T> Foo<T>::foo3() 
    46 {
    47 
    48 }
    49 
    50 template<typename T>
    51 template <typename U>
    52 void Foo<T>::swap(U x) 
    53 {
    54 
    55 }
    56 
    57 Foo<int>::Handle
    58 Foo<int>::foo(Node a) 
    59 {
    60 
    61 }
    62 
    63 template <typename T>
    64 Foo<T*>::Handle
    65 Foo<T*>::foo(Node a) 
    66 {
    67 
    68 }
    69 
    70 //Hand<int> Foo<int>::foo(Node a) 
    71 //{
    72 //  cout << "int foo" << endl;
    73 //}
    74 //
    75 template <typename T>
    76 void print(T x) 
    77 {
    78 
    79 }
    80 

     // openmesh 中的一个头文件PolyMeshT.hh生成实现文件框架的示例

    //PolyMeshT.hh

      1 /*===========================================================================*\
      2  *                                                                           *
      3  *                               OpenMesh                                    *
      4  *      Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen      *
      5 //=============================================================================
      6 //
      7 //  CLASS PolyMeshT
      8 //
      9 //=============================================================================
     10 
     11 
     12 #ifndef OPENMESH_POLYMESHT_HH
     13 #define OPENMESH_POLYMESHT_HH
     14 
     15 
     16 //== INCLUDES =================================================================
     17 
     18 
     19 #include <OpenMesh/Core/System/config.h>
     20 #include <OpenMesh/Core/Geometry/MathDefs.hh>
     21 #include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
     22 #include <vector>
     23 
     24 
     25 //== NAMESPACES ===============================================================
     26 
     27 
     28 namespace OpenMesh {
     29 
     30 
     31 //== CLASS DEFINITION =========================================================
     32 
     33 
     34 /** \class PolyMeshT PolyMeshT.hh <OpenMesh/Mesh/PolyMeshT.hh>
     35 
     36     Base type for a polygonal mesh.
     37 
     38     This is the base class for a polygonal mesh. It is parameterized
     39     by a mesh kernel that is given as a template argument. This class
     40     inherits all methods from its mesh kernel.
     41 
     42     \param Kernel: template argument for the mesh kernel
     43     \note You should use the predefined mesh-kernel combinations in
     44     \ref mesh_types_group
     45     \see \ref mesh_type
     46 */
     47 
     48 template <class Kernel>
     49 class PolyMeshT : public Kernel
     50 {
     51 public:
     52 
     53   /// Self type. Used to specify iterators/circulators.
     54   typedef PolyMeshT<Kernel>                   This;
     55   //--- item types ---
     56 
     57   //@{
     58   /// Determine whether this is a PolyMeshT or TriMeshT ( This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT )
     59   enum { IsPolyMesh = 1 };
     60   enum { IsTriMesh  = 0 };
     61   static bool is_polymesh() { return true;  }
     62   static bool is_trimesh()  { return false; }
     63   //@}
     64 
     65   /// \name Mesh Items
     66   //@{
     67   /// Scalar type
     68   typedef typename Kernel::Scalar    Scalar;
     69   /// Coordinate type
     70   typedef typename Kernel::Point     Point;
     71   /// Normal type
     72   typedef typename Kernel::Normal    Normal;
     73   /// Color type
     74   typedef typename Kernel::Color     Color;
     75   /// TexCoord1D type
     76   typedef typename Kernel::TexCoord1D  TexCoord1D;
     77   /// TexCoord2D type
     78   typedef typename Kernel::TexCoord2D  TexCoord2D;
     79   /// TexCoord3D type
     80   typedef typename Kernel::TexCoord3D  TexCoord3D;
     81   /// Vertex type
     82   typedef typename Kernel::Vertex    Vertex;
     83   /// Halfedge type
     84   typedef typename Kernel::Halfedge  Halfedge;
     85   /// Edge type
     86   typedef typename Kernel::Edge      Edge;
     87   /// Face type
     88   typedef typename Kernel::Face      Face;
     89   //@}
     90 
     91   //--- handle types ---
     92 
     93   /// Handle for referencing the corresponding item
     94   typedef typename Kernel::VertexHandle       VertexHandle;
     95   typedef typename Kernel::HalfedgeHandle     HalfedgeHandle;
     96   typedef typename Kernel::EdgeHandle         EdgeHandle;
     97   typedef typename Kernel::FaceHandle         FaceHandle;
     98 
     99 
    100 
    101   typedef typename Kernel::VertexIter                 VertexIter;
    102   typedef typename Kernel::HalfedgeIter               HalfedgeIter;
    103   typedef typename Kernel::EdgeIter                   EdgeIter;
    104   typedef typename Kernel::FaceIter                   FaceIter;
    105 
    106   typedef typename Kernel::ConstVertexIter            ConstVertexIter;
    107   typedef typename Kernel::ConstHalfedgeIter          ConstHalfedgeIter;
    108   typedef typename Kernel::ConstEdgeIter              ConstEdgeIter;
    109   typedef typename Kernel::ConstFaceIter              ConstFaceIter;
    110   //@}
    111 
    112   //--- circulators ---
    113 
    114   /** \name Mesh Circulators
    115       Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators
    116       for documentation.
    117   */
    118   //@{
    119   /// Circulator
    120   typedef typename Kernel::VertexVertexIter          VertexVertexIter;
    121   typedef typename Kernel::VertexOHalfedgeIter       VertexOHalfedgeIter;
    122   typedef typename Kernel::VertexIHalfedgeIter       VertexIHalfedgeIter;
    123   typedef typename Kernel::VertexEdgeIter            VertexEdgeIter;
    124   typedef typename Kernel::VertexFaceIter            VertexFaceIter;
    125   typedef typename Kernel::FaceVertexIter            FaceVertexIter;
    126   typedef typename Kernel::FaceHalfedgeIter          FaceHalfedgeIter;
    127   typedef typename Kernel::FaceEdgeIter              FaceEdgeIter;
    128   typedef typename Kernel::FaceFaceIter              FaceFaceIter;
    129 
    130   typedef typename Kernel::ConstVertexVertexIter     ConstVertexVertexIter;
    131   typedef typename Kernel::ConstVertexOHalfedgeIter  ConstVertexOHalfedgeIter;
    132   typedef typename Kernel::ConstVertexIHalfedgeIter  ConstVertexIHalfedgeIter;
    133   typedef typename Kernel::ConstVertexEdgeIter       ConstVertexEdgeIter;
    134   typedef typename Kernel::ConstVertexFaceIter       ConstVertexFaceIter;
    135   typedef typename Kernel::ConstFaceVertexIter       ConstFaceVertexIter;
    136   typedef typename Kernel::ConstFaceHalfedgeIter     ConstFaceHalfedgeIter;
    137   typedef typename Kernel::ConstFaceEdgeIter         ConstFaceEdgeIter;
    138   typedef typename Kernel::ConstFaceFaceIter         ConstFaceFaceIter;
    139   //@}
    140 
    141 
    142   // --- constructor/destructor
    143   PolyMeshT() {}
    144   virtual ~PolyMeshT() {}
    145 
    146   /** Uses default copy and assignment operator.
    147       Use them to assign two meshes of \b equal type.
    148       If the mesh types vary, use PolyMeshT::assign() instead. */
    149 
    150    // --- creation ---
    151   inline VertexHandle new_vertex()
    152   { return Kernel::new_vertex(); }
    153 
    154   inline VertexHandle new_vertex(const Point& _p)
    155   {
    156     VertexHandle vh(Kernel::new_vertex());
    157     set_point(vh, _p);
    158     return vh;
    159   }
    160 
    161   inline VertexHandle add_vertex(const Point& _p)
    162   { return new_vertex(_p); }
    163 
    164   // --- normal vectors ---
    165 
    166   /** \name Normal vector computation
    167   */
    168   //@{
    169 
    170   /** Calls update_face_normals() and update_vertex_normals() if
    171       these normals (i.e. the properties) exist */
    172   void update_normals();
    173 
    174   /// Update normal for face _fh
    175   void update_normal(FaceHandle _fh)
    176   { set_normal(_fh, calc_face_normal(_fh)); }
    177 
    178   /** Update normal vectors for all faces.
    179       \attention Needs the Attributes::Normal attribute for faces. */
    180   void update_face_normals();
    181 
    182   /** Calculate normal vector for face _fh. */
    183   Normal calc_face_normal(FaceHandle _fh) const;
    184 
    185   /** Calculate normal vector for face (_p0, _p1, _p2). */
    186   Normal calc_face_normal(const Point& _p0, const Point& _p1,
    187                                             const Point& _p2) const;
    188   // calculates the average of the vertices defining _fh
    189   void calc_face_centroid(FaceHandle _fh, Point& _pt) const;
    190   /// Update normal for vertex _vh
    191   void update_normal(VertexHandle _vh)
    192   { set_normal(_vh, calc_vertex_normal(_vh)); }
    193 
    194   /** Update normal vectors for all vertices. \attention Needs the
    195       Attributes::Normal attribute for faces and vertices. */
    196   void update_vertex_normals();
    197 
    198   /** Calculate normal vector for vertex _vh by averaging normals
    199       of adjacent faces. Face normals have to be computed first.
    200       \attention Needs the Attributes::Normal attribute for faces. */
    201   Normal calc_vertex_normal(VertexHandle _vh) const;
    202 
    203   /** Different methods for calculation of the normal at _vh:
    204       - -"-_fast    - the default one - the same as calc vertex_normal()
    205                     - needs the Attributes::Normal attribute for faces
    206       - -"-_correct - works properly for non-triangular meshes
    207                     - does not need any attributes
    208       - -"-_loop    - calculates loop surface normals
    209                     - does not need any attributes */
    210   void calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const;
    211   void calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const;
    212   void calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const;
    213 
    214 
    215   //@}
    216 
    217   // --- Geometry API - still in development ---
    218 
    219   /** Calculates the edge vector as the vector defined by
    220       the halfedge with id #0 (see below)  */
    221   void calc_edge_vector(EdgeHandle _eh, Normal& _edge_vec) const
    222   { calc_edge_vector(halfedge_handle(_eh,0), _edge_vec); }
    223 
    224   /** Calculates the edge vector as the difference of the
    225       the points defined by to_vertex_handle() and from_vertex_handle() */
    226   void calc_edge_vector(HalfedgeHandle _heh, Normal& _edge_vec) const
    227   {
    228     _edge_vec = point(to_vertex_handle(_heh));
    229     _edge_vec -= point(from_vertex_handle(_heh));
    230   }
    231 
    232   // Calculates the length of the edge _eh
    233   Scalar calc_edge_length(EdgeHandle _eh) const
    234   { return calc_edge_length(halfedge_handle(_eh,0)); }
    235 
    236   /** Calculates the length of the edge _heh
    237   */
    238   Scalar calc_edge_length(HalfedgeHandle _heh) const
    239   { return (Scalar)sqrt(calc_edge_sqr_length(_heh)); }
    240 
    241   Scalar calc_edge_sqr_length(EdgeHandle _eh) const
    242   { return calc_edge_sqr_length(halfedge_handle(_eh,0)); }
    243 
    244   Scalar calc_edge_sqr_length(HalfedgeHandle _heh) const
    245   {
    246     Normal edge_vec;
    247     calc_edge_vector(_heh, edge_vec);
    248     return edge_vec.sqrnorm();
    249   }
    250 
    251   /** defines a consistent representation of a sector geometry:
    252       the halfedge _in_heh defines the sector orientation
    253       the vertex pointed by _in_heh defines the sector center
    254       _vec0 and _vec1 are resp. the first and the second vectors defining the sector */
    255   void calc_sector_vectors(HalfedgeHandle _in_heh, Normal& _vec0, Normal& _vec1) const
    256   {
    257     calc_edge_vector(next_halfedge_handle(_in_heh), _vec0);//p2 - p1
    258     calc_edge_vector(opposite_halfedge_handle(_in_heh), _vec1);//p0 - p1
    259   }
    260 
    261   /** calculates the sector angle.\n
    262    * The vertex pointed by _in_heh defines the sector center
    263    * The angle will be calculated between the given halfedge and the next halfedge.\n
    264    * Seen from the center vertex this will be the next halfedge in clockwise direction.\n
    265       NOTE: only boundary concave sectors are treated correctly */
    266   Scalar calc_sector_angle(HalfedgeHandle _in_heh) const
    267   {
    268     Normal v0, v1;
    269     calc_sector_vectors(_in_heh, v0, v1);
    270     Scalar denom = v0.norm()*v1.norm();
    271     if (is_zero(denom))
    272     {
    273       return 0;
    274     }
    275     Scalar cos_a = (v0 | v1) / denom;
    276     if (is_boundary(_in_heh))
    277     {//determine if the boundary sector is concave or convex
    278       FaceHandle fh(face_handle(opposite_halfedge_handle(_in_heh)));
    279       Normal f_n(calc_face_normal(fh));//this normal is (for convex fh) OK
    280       Scalar sign_a = dot(cross(v0, v1), f_n);
    281       return angle(cos_a, sign_a);
    282     }
    283     else
    284     {
    285       return acos(sane_aarg(cos_a));
    286     }
    287   }
    288 
    289   // calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh))
    290   /*
    291   void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const
    292   {
    293     Normal in_vec, out_vec;
    294     calc_edge_vector(_in_heh, in_vec);
    295     calc_edge_vector(next_halfedge_handle(_in_heh), out_vec);
    296     Scalar denom = in_vec.norm()*out_vec.norm();
    297     if (is_zero(denom))
    298     {
    299       _cos_a = 1;
    300       _sin_a = 0;
    301     }
    302     else
    303     {
    304       _cos_a = dot(in_vec, out_vec)/denom;
    305       _sin_a = cross(in_vec, out_vec).norm()/denom;
    306     }
    307   }
    308   */
    309   /** calculates the normal (non-normalized) of the face sector defined by
    310       the angle <(_in_heh,next_halfedge(_in_heh)) */
    311   void calc_sector_normal(HalfedgeHandle _in_heh, Normal& _sector_normal) const
    312   {
    313     Normal vec0, vec1;
    314     calc_sector_vectors(_in_heh, vec0, vec1);
    315     _sector_normal = cross(vec0, vec1);//(p2-p1)^(p0-p1)
    316   }
    317 
    318   /** calculates the area of the face sector defined by
    319       the angle <(_in_heh,next_halfedge(_in_heh))
    320       NOTE: special cases (e.g. concave sectors) are not handled correctly */
    321   Scalar calc_sector_area(HalfedgeHandle _in_heh) const
    322   {
    323     Normal sector_normal;
    324     calc_sector_normal(_in_heh, sector_normal);
    325     return sector_normal.norm()/2;
    326   }
    327 
    328   /** calculates the dihedral angle on the halfedge _heh
    329       \attention Needs the Attributes::Normal attribute for faces */
    330   Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh) const
    331   {
    332     CHECK(Kernel::has_face_normals());
    333     if (is_boundary(edge_handle(_heh)))
    334     {//the dihedral angle at a boundary edge is 0
    335       return 0;
    336     }
    337     const Normal& n0 = normal(face_handle(_heh));
    338     const Normal& n1 = normal(face_handle(opposite_halfedge_handle(_heh)));
    339     Normal he;
    340     calc_edge_vector(_heh, he);
    341     Scalar da_cos = dot(n0, n1);
    342     //should be normalized, but we need only the sign
    343     Scalar da_sin_sign = dot(cross(n0, n1), he);
    344     return angle(da_cos, da_sin_sign);
    345   }
    346 
    347   /** calculates the dihedral angle on the edge _eh
    348       \attention Needs the Attributes::Normal attribute for faces */
    349   Scalar calc_dihedral_angle_fast(EdgeHandle _eh) const
    350   { return calc_dihedral_angle_fast(halfedge_handle(_eh,0)); }
    351 
    352   // calculates the dihedral angle on the halfedge _heh
    353   Scalar calc_dihedral_angle(HalfedgeHandle _heh) const
    354   {
    355     if (is_boundary(edge_handle(_heh)))
    356     {//the dihedral angle at a boundary edge is 0
    357       return 0;
    358     }
    359     Normal n0, n1, he;
    360     calc_sector_normal(_heh, n0);
    361     calc_sector_normal(opposite_halfedge_handle(_heh), n1);
    362     calc_edge_vector(_heh, he);
    363     Scalar denom = n0.norm()*n1.norm();
    364     if (denom == Scalar(0))
    365     {
    366       return 0;
    367     }
    368     Scalar da_cos = dot(n0, n1)/denom;
    369     //should be normalized, but we need only the sign
    370     Scalar da_sin_sign = dot(cross(n0, n1), he);
    371     return angle(da_cos, da_sin_sign);
    372   }
    373 
    374   // calculates the dihedral angle on the edge _eh
    375   Scalar calc_dihedral_angle(EdgeHandle _eh) const
    376   { return calc_dihedral_angle(halfedge_handle(_eh,0)); }
    377 
    378   /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh
    379       returns the number of the found feature edges, requires edge_status property*/
    380   uint find_feature_edges(Scalar _angle_tresh = OpenMesh::deg_to_rad(44.0));
    381   // --- misc ---
    382 
    383   /// Face split (= 1-to-n split)
    384   inline void split(FaceHandle _fh, const Point& _p)
    385   { Kernel::split(_fh, add_vertex(_p)); }
    386 
    387   inline void split(FaceHandle _fh, VertexHandle _vh)
    388   { Kernel::split(_fh, _vh); }
    389 
    390   inline void split(EdgeHandle _eh, const Point& _p)
    391   { Kernel::split(_eh, add_vertex(_p)); }
    392 
    393   inline void split(EdgeHandle _eh, VertexHandle _vh)
    394   { Kernel::split(_eh, _vh); }
    395 };
    396 
    397 
    398 //=============================================================================
    399 // namespace OpenMesh
    400 //=============================================================================
    401 #if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C)
    402 #  define OPENMESH_POLYMESH_TEMPLATES
    403 #  include "PolyMeshT.cc"
    404 #endif
    405 //=============================================================================
    406 #endif // OPENMESH_POLYMESHT_HH defined
    407 //=============================================================================

    408

    //用h2cc.py生成的实现文件框架PolyMeshT.cpp

     //PolyMeshT.cpp  #h2cc.py自动生成

         1 #include "PolyMeshT.hh"

      2 
      3 namespace OpenMesh {
      4 
      5 /** Calls update_face_normals() and update_vertex_normals() if
      6 these normals (i.e. the properties) exist */
      7 template <class Kernel>
      8 void PolyMeshT<Kernel>::update_normals() 
      9 {
     10 
     11 }
     12 
     13 /** Update normal vectors for all faces.
     14 \attention Needs the Attributes::Normal attribute for faces. */
     15 template <class Kernel>
     16 void PolyMeshT<Kernel>::update_face_normals() 
     17 {
     18 
     19 }
     20 
     21 /** Calculate normal vector for face _fh. */
     22 template <class Kernel>
     23 typename PolyMeshT::Normal
     24 PolyMeshT<Kernel>::
     25 calc_face_normal(FaceHandle _fh) const 
     26 {
     27 
     28 }
     29 
     30 /** Calculate normal vector for face (_p0, _p1, _p2). */
     31 template <class Kernel>
     32 typename PolyMeshT::Normal
     33 PolyMeshT<Kernel>::
     34 calc_face_normal(const Point& _p0, const Point& _p1,
     35                                           const Point& _p2) const 
     36 {
     37 
     38 }
     39 
     40 // calculates the average of the vertices defining _fh
     41 template <class Kernel>
     42 void PolyMeshT<Kernel>::
     43 calc_face_centroid(FaceHandle _fh, Point& _pt) const 
     44 {
     45 
     46 }
     47 
     48 /** Update normal vectors for all vertices. \attention Needs the
     49 Attributes::Normal attribute for faces and vertices. */
     50 template <class Kernel>
     51 void PolyMeshT<Kernel>::update_vertex_normals() 
     52 {
     53 
     54 }
     55 
     56 /** Calculate normal vector for vertex _vh by averaging normals
     57 of adjacent faces. Face normals have to be computed first.
     58 \attention Needs the Attributes::Normal attribute for faces. */
     59 template <class Kernel>
     60 typename PolyMeshT::Normal
     61 PolyMeshT<Kernel>::
     62 calc_vertex_normal(VertexHandle _vh) const 
     63 {
     64 
     65 }
     66 
     67 /** Different methods for calculation of the normal at _vh:
     68 - -"-_fast    - the default one - the same as calc vertex_normal()
     69 - needs the Attributes::Normal attribute for faces
     70 - -"-_correct - works properly for non-triangular meshes
     71 - does not need any attributes
     72 - -"-_loop    - calculates loop surface normals
     73 - does not need any attributes */
     74 template <class Kernel>
     75 void PolyMeshT<Kernel>::
     76 calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const 
     77 {
     78 
     79 }
     80 
     81 template <class Kernel>
     82 void PolyMeshT<Kernel>::
     83 calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const 
     84 {
     85 
     86 }
     87 
     88 template <class Kernel>
     89 void PolyMeshT<Kernel>::
     90 calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const 
     91 {
     92 
     93 }
     94 
     95 /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh
     96 returns the number of the found feature edges, requires edge_status property*/
     97 template <class Kernel>
     98 uint PolyMeshT<Kernel>::
     99 find_feature_edges(Scalar _angle_tresh) 
    100 {
    101 
    102 }
    103 
    104 // namespace OpenMesh
    105 

    //Openmesh提供的对应PolyMeshT.hh的实现文件PolyMeshT.cc可以和上面自动生成的框架对比一下:) 

       1 //=============================================================================

      2 //
      3 //  CLASS PolyMeshT - IMPLEMENTATION
      4 //
      5 //=============================================================================
      6 
      7 
      8 #define OPENMESH_POLYMESH_C
      9 
     10 
     11 //== INCLUDES =================================================================
     12 
     13 #include <OpenMesh/Core/Mesh/PolyMeshT.hh>
     14 #include <OpenMesh/Core/Geometry/LoopSchemeMaskT.hh>
     15 #include <OpenMesh/Core/Utils/vector_cast.hh>
     16 #include <OpenMesh/Core/System/omstream.hh>
     17 #include <vector>
     18 
     19 
     20 //== NAMESPACES ===============================================================
     21 
     22 
     23 namespace OpenMesh {
     24 
     25 //== IMPLEMENTATION ==========================================================
     26 
     27 template <class Kernel>
     28 uint PolyMeshT<Kernel>::find_feature_edges(Scalar _angle_tresh)
     29 {
     30   assert(Kernel::has_edge_status());//this function needs edge status property
     31   uint n_feature_edges = 0;
     32   for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it)
     33   {
     34     if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh)
     35     {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
     36       status(e_it).set_feature(true);
     37       n_feature_edges++;
     38     }
     39     else
     40     {
     41       status(e_it).set_feature(false);
     42     }
     43   }
     44   return n_feature_edges;
     45 }
     46 
     47 //-----------------------------------------------------------------------------
     48 
     49 template <class Kernel>
     50 typename PolyMeshT<Kernel>::Normal
     51 PolyMeshT<Kernel>::
     52 calc_face_normal(FaceHandle _fh) const
     53 {
     54   assert(halfedge_handle(_fh).is_valid());
     55   ConstFaceVertexIter fv_it(cfv_iter(_fh));
     56 
     57   const Point& p0(point(fv_it));  ++fv_it;
     58   const Point& p1(point(fv_it));  ++fv_it;
     59   const Point& p2(point(fv_it));
     60 
     61   return calc_face_normal(p0, p1, p2);
     62 }
     63 
     64 
     65 //-----------------------------------------------------------------------------
     66 
     67 
     68 template <class Kernel>
     69 typename PolyMeshT<Kernel>::Normal
     70 PolyMeshT<Kernel>::
     71 calc_face_normal(const Point& _p0,
     72      const Point& _p1,
     73      const Point& _p2) const
     74 {
     75 #if 1
     76   // The OpenSG <Vector>::operator -= () does not support the type Point
     77   // as rhs. Therefore use vector_cast at this point!!!
     78   // Note! OpenSG distinguishes between Normal and Point!!!
     79   Normal p1p0(_p0);  p1p0 -= vector_cast<Normal>(_p1);
     80   Normal p1p2(_p2);  p1p2 -= vector_cast<Normal>(_p1);
     81 
     82   Normal n    = cross(p1p2, p1p0);
     83   Scalar norm = n.length();
     84 
     85   // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
     86   // vector class does not return self after component-wise
     87   // self-multiplication with a scalar!!!
     88   return (norm != Scalar(0)) ? ((n *= (Scalar(1)/norm)),n) : Normal(0,0,0);
     89 #else
     90   Point p1p0 = _p0;  p1p0 -= _p1;
     91   Point p1p2 = _p2;  p1p2 -= _p1;
     92 
     93   Normal n = vector_cast<Normal>(cross(p1p2, p1p0));
     94   Scalar norm = n.length();
     95 
     96   return (norm != 0.0? n *= (1.0/norm) : Normal(0,0,0);
     97 #endif
     98 }
     99 
    100 //-----------------------------------------------------------------------------
    101 
    102 template <class Kernel>
    103 void
    104 PolyMeshT<Kernel>::
    105 calc_face_centroid(FaceHandle _fh, Point& _pt) const
    106 {
    107   _pt.vectorize(0);
    108   uint valence = 0;
    109   for (ConstFaceVertexIter cfv_it = cfv_iter(_fh); cfv_it; ++cfv_it, ++valence)
    110   {
    111     _pt += point(cfv_it);
    112   }
    113   _pt /= valence;
    114 }
    115 //-----------------------------------------------------------------------------
    116 
    117 
    118 template <class Kernel>
    119 void
    120 PolyMeshT<Kernel>::
    121 update_normals()
    122 {
    123   if (Kernel::has_face_normals())    update_face_normals();
    124   if (Kernel::has_vertex_normals())  update_vertex_normals();
    125 }
    126 
    127 
    128 //-----------------------------------------------------------------------------
    129 
    130 
    131 template <class Kernel>
    132 void
    133 PolyMeshT<Kernel>::
    134 update_face_normals()
    135 {
    136   FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());
    137 
    138   for (; f_it != f_end; ++f_it)
    139     set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
    140 }
    141 
    142 
    143 //-----------------------------------------------------------------------------
    144 
    145 
    146 template <class Kernel>
    147 typename PolyMeshT<Kernel>::Normal
    148 PolyMeshT<Kernel>::
    149 calc_vertex_normal(VertexHandle _vh) const
    150 {
    151   Normal n;
    152   calc_vertex_normal_fast(_vh,n);
    153 
    154   Scalar norm = n.length();
    155   if (norm != 0.0) n *= (1.0/norm);
    156 
    157   return n;
    158 }
    159 
    160 //-----------------------------------------------------------------------------
    161 template <class Kernel>
    162 void PolyMeshT<Kernel>::
    163 calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const
    164 {
    165   _n.vectorize(0.0);
    166   for (ConstVertexFaceIter vf_it=cvf_iter(_vh); vf_it; ++vf_it)
    167     _n += normal(vf_it.handle());
    168 }
    169 
    170 //-----------------------------------------------------------------------------
    171 template <class Kernel>
    172 void PolyMeshT<Kernel>::
    173 calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const
    174 {
    175   _n.vectorize(0.0);
    176   ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh);
    177   if (!cvih_it)
    178   {//don't crash on isolated vertices
    179     return;
    180   }
    181   Normal in_he_vec;
    182   calc_edge_vector(cvih_it, in_he_vec);
    183   for ( ; cvih_it; ++cvih_it)
    184   {//calculates the sector normal defined by cvih_it and adds it to _n
    185     if (is_boundary(cvih_it))
    186     {
    187       continue;
    188     }
    189     HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
    190     Normal out_he_vec;
    191     calc_edge_vector(out_heh, out_he_vec);
    192     _n += cross(in_he_vec, out_he_vec);//sector area is taken into account
    193     in_he_vec = out_he_vec;
    194     in_he_vec *= -1;//change the orientation
    195   }
    196 }
    197 
    198 //-----------------------------------------------------------------------------
    199 template <class Kernel>
    200 void PolyMeshT<Kernel>::
    201 calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const
    202 {
    203   static const LoopSchemeMaskDouble& loop_scheme_mask__ =
    204                   LoopSchemeMaskDoubleSingleton::Instance();
    205 
    206   Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0);
    207   unsigned int vh_val = valence(_vh);
    208   unsigned int i = 0;
    209   for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i)
    210   {
    211     VertexHandle r1_v(to_vertex_handle(cvoh_it));
    212     t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*point(r1_v);
    213     t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*point(r1_v);
    214   }
    215   _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed?
    216 }
    217 
    218 //-----------------------------------------------------------------------------
    219 
    220 
    221 template <class Kernel>
    222 void
    223 PolyMeshT<Kernel>::
    224 update_vertex_normals()
    225 {
    226   VertexIter  v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());
    227 
    228   for (; v_it!=v_end; ++v_it)
    229     set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
    230 }
    231 
    232 //=============================================================================
    233 // namespace OpenMesh
    234 //=============================================================================
    235 

    //看一个非模版类的示例,google test的一个头文件  gtest-filepath.h

      1 
      2 #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
      3 #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
      4 
      5 #include <gtest/internal/gtest-string.h>
      6 
      7 namespace testing {
      8 namespace internal {
      9 
     10 // FilePath - a class for file and directory pathname manipulation which
     11 // handles platform-specific conventions (like the pathname separator).
     12 // Used for helper functions for naming files in a directory for xml output.
     13 // Except for Set methods, all methods are const or static, which provides an
     14 // "immutable value object" -- useful for peace of mind.
     15 // A FilePath with a value ending in a path separator ("like/this/") represents
     16 // a directory, otherwise it is assumed to represent a file. In either case,
     17 // it may or may not represent an actual file or directory in the file system.
     18 // Names are NOT checked for syntax correctness -- no checking for illegal
     19 // characters, malformed paths, etc.
     20 
     21 class FilePath {
     22  public:
     23   FilePath() : pathname_("") { }
     24   FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
     25 
     26   explicit FilePath(const char* pathname) : pathname_(pathname) {
     27     Normalize();
     28   }
     29 
     30   explicit FilePath(const String& pathname) : pathname_(pathname) {
     31     Normalize();
     32   }
     33 
     34   FilePath& operator=(const FilePath& rhs) {
     35     Set(rhs);
     36     return *this;
     37   }
     38 
     39   void Set(const FilePath& rhs) {
     40     pathname_ = rhs.pathname_;
     41   }
     42 
     43   String ToString() const { return pathname_; }
     44   const char* c_str() const { return pathname_.c_str(); }
     45 
     46   // Returns the current working directory, or "" if unsuccessful.
     47   static FilePath GetCurrentDir();
     48 
     49   // Given directory = "dir", base_name = "test", number = 0,
     50   // extension = "xml", returns "dir/test.xml". If number is greater
     51   // than zero (e.g., 12), returns "dir/test_12.xml".
     52   // On Windows platform, uses \ as the separator rather than /.
     53   static FilePath MakeFileName(const FilePath& directory,
     54                                const FilePath& base_name,
     55                                int number,
     56                                const char* extension);
     57 
     58   // Given directory = "dir", relative_path = "test.xml",
     59   // returns "dir/test.xml".
     60   // On Windows, uses \ as the separator rather than /.
     61   static FilePath ConcatPaths(const FilePath& directory,
     62                               const FilePath& relative_path);
     63 
     64   // Returns a pathname for a file that does not currently exist. The pathname
     65   // will be directory/base_name.extension or
     66   // directory/base_name_<number>.extension if directory/base_name.extension
     67   // already exists. The number will be incremented until a pathname is found
     68   // that does not already exist.
     69   // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
     70   // There could be a race condition if two or more processes are calling this
     71   // function at the same time -- they could both pick the same filename.
     72   static FilePath GenerateUniqueFileName(const FilePath& directory,
     73                                          const FilePath& base_name,
     74                                          const char* extension);
     75 
     76   // Returns true iff the path is NULL or "".
     77   bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
     78 
     79   // If input name has a trailing separator character, removes it and returns
     80   // the name, otherwise return the name string unmodified.
     81   // On Windows platform, uses \ as the separator, other platforms use /.
     82   FilePath RemoveTrailingPathSeparator() const;
     83 
     84   // Returns a copy of the FilePath with the directory part removed.
     85   // Example: FilePath("path/to/file").RemoveDirectoryName() returns
     86   // FilePath("file"). If there is no directory part ("just_a_file"), it returns
     87   // the FilePath unmodified. If there is no file part ("just_a_dir/") it
     88   // returns an empty FilePath ("").
     89   // On Windows platform, '\' is the path separator, otherwise it is '/'.
     90   FilePath RemoveDirectoryName() const;
     91 
     92   // RemoveFileName returns the directory path with the filename removed.
     93   // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
     94   // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
     95   // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
     96   // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
     97   // On Windows platform, '\' is the path separator, otherwise it is '/'.
     98   FilePath RemoveFileName() const;
     99 
    100   // Returns a copy of the FilePath with the case-insensitive extension removed.
    101   // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
    102   // FilePath("dir/file"). If a case-insensitive extension is not
    103   // found, returns a copy of the original FilePath.
    104   FilePath RemoveExtension(const char* extension) const;
    105 
    106   // Creates directories so that path exists. Returns true if successful or if
    107   // the directories already exist; returns false if unable to create
    108   // directories for any reason. Will also return false if the FilePath does
    109   // not represent a directory (that is, it doesn't end with a path separator).
    110   bool CreateDirectoriesRecursively() const;
    111 
    112   // Create the directory so that path exists. Returns true if successful or
    113   // if the directory already exists; returns false if unable to create the
    114   // directory for any reason, including if the parent directory does not
    115   // exist. Not named "CreateDirectory" because that's a macro on Windows.
    116   bool CreateFolder() const;
    117 
    118   // Returns true if FilePath describes something in the file-system,
    119   // either a file, directory, or whatever, and that something exists.
    120   bool FileOrDirectoryExists() const;
    121 
    122   // Returns true if pathname describes a directory in the file-system
    123   // that exists.
    124   bool DirectoryExists() const;
    125 
    126   // Returns true if FilePath ends with a path separator, which indicates that
    127   // it is intended to represent a directory. Returns false otherwise.
    128   // This does NOT check that a directory (or file) actually exists.
    129   bool IsDirectory() const;
    130 
    131   // Returns true if pathname describes a root directory. (Windows has one
    132   // root directory per disk drive.)
    133   bool IsRootDirectory() const;
    134 
    135   // Returns true if pathname describes an absolute path.
    136   bool IsAbsolutePath() const;
    137 
    138  private:
    139   // Replaces multiple consecutive separators with a single separator.
    140   // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
    141   // redundancies that might be in a pathname involving "." or "..".
    142   //
    143   // A pathname with multiple consecutive separators may occur either through
    144   // user error or as a result of some scripts or APIs that generate a pathname
    145   // with a trailing separator. On other platforms the same API or script
    146   // may NOT generate a pathname with a trailing "/". Then elsewhere that
    147   // pathname may have another "/" and pathname components added to it,
    148   // without checking for the separator already being there.
    149   // The script language and operating system may allow paths like "foo//bar"
    150   // but some of the functions in FilePath will not handle that correctly. In
    151   // particular, RemoveTrailingPathSeparator() only removes one separator, and
    152   // it is called in CreateDirectoriesRecursively() assuming that it will change
    153   // a pathname from directory syntax (trailing separator) to filename syntax.
    154 
    155   void Normalize();
    156 
    157   String pathname_;
    158 };  // class FilePath
    159 
    160 }  // namespace internal
    161 }  // namespace testing
    162 
    163 #endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_

    164  

     //由h2cc.py生成的 gtest-filepath.cc实现框架

        1 #include "gtest-filepath.h"

      2 
      3 namespace testing {
      4 
      5 namespace internal {
      6 
      7 // Returns the current working directory, or "" if unsuccessful.
      8 FilePath FilePath::GetCurrentDir() 
      9 {
     10 
     11 }
     12 
     13 // Given directory = "dir", base_name = "test", number = 0,
     14 // extension = "xml", returns "dir/test.xml". If number is greater
     15 // than zero (e.g., 12), returns "dir/test_12.xml".
     16 // On Windows platform, uses \ as the separator rather than /.
     17 FilePath FilePath::
     18 MakeFileName(const FilePath& directory,
     19                              const FilePath& base_name,
     20                              int number,
     21                              const char* extension) 
     22 {
     23 
     24 }
     25 
     26 // Given directory = "dir", relative_path = "test.xml",
     27 // returns "dir/test.xml".
     28 // On Windows, uses \ as the separator rather than /.
     29 FilePath FilePath::
     30 ConcatPaths(const FilePath& directory,
     31                             const FilePath& relative_path) 
     32 {
     33 
     34 }
     35 
     36 // Returns a pathname for a file that does not currently exist. The pathname
     37 // will be directory/base_name.extension or
     38 // directory/base_name_<number>.extension if directory/base_name.extension
     39 // already exists. The number will be incremented until a pathname is found
     40 // that does not already exist.
     41 // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
     42 // There could be a race condition if two or more processes are calling this
     43 // function at the same time -- they could both pick the same filename.
     44 FilePath FilePath::
     45 GenerateUniqueFileName(const FilePath& directory,
     46                                        const FilePath& base_name,
     47                                        const char* extension) 
     48 {
     49 
     50 }
     51 
     52 // If input name has a trailing separator character, removes it and returns
     53 // the name, otherwise return the name string unmodified.
     54 // On Windows platform, uses \ as the separator, other platforms use /.
     55 FilePath FilePath::
     56 RemoveTrailingPathSeparator() const 
     57 {
     58 
     59 }
     60 
     61 // Returns a copy of the FilePath with the directory part removed.
     62 // Example: FilePath("path/to/file").RemoveDirectoryName() returns
     63 // FilePath("file"). If there is no directory part ("just_a_file"), it returns
     64 // the FilePath unmodified. If there is no file part ("just_a_dir/") it
     65 // returns an empty FilePath ("").
     66 // On Windows platform, '\' is the path separator, otherwise it is '/'.
     67 FilePath FilePath::RemoveDirectoryName() const 
     68 {
     69 
     70 }
     71 
     72 // RemoveFileName returns the directory path with the filename removed.
     73 // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
     74 // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
     75 // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
     76 // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
     77 // On Windows platform, '\' is the path separator, otherwise it is '/'.
     78 FilePath FilePath::RemoveFileName() const 
     79 {
     80 
     81 }
     82 
     83 // Returns a copy of the FilePath with the case-insensitive extension removed.
     84 // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
     85 // FilePath("dir/file"). If a case-insensitive extension is not
     86 // found, returns a copy of the original FilePath.
     87 FilePath FilePath::
     88 RemoveExtension(const char* extension) const 
     89 {
     90 
     91 }
     92 
     93 // Creates directories so that path exists. Returns true if successful or if
     94 // the directories already exist; returns false if unable to create
     95 // directories for any reason. Will also return false if the FilePath does
     96 // not represent a directory (that is, it doesn't end with a path separator).
     97 bool FilePath::CreateDirectoriesRecursively() const 
     98 {
     99 
    100 }
    101 
    102 // Create the directory so that path exists. Returns true if successful or
    103 // if the directory already exists; returns false if unable to create the
    104 // directory for any reason, including if the parent directory does not
    105 // exist. Not named "CreateDirectory" because that's a macro on Windows.
    106 bool FilePath::CreateFolder() const 
    107 {
    108 
    109 }
    110 
    111 // Returns true if FilePath describes something in the file-system,
    112 // either a file, directory, or whatever, and that something exists.
    113 bool FilePath::FileOrDirectoryExists() const 
    114 {
    115 
    116 }
    117 
    118 // Returns true if pathname describes a directory in the file-system
    119 // that exists.
    120 bool FilePath::DirectoryExists() const 
    121 {
    122 
    123 }
    124 
    125 // Returns true if FilePath ends with a path separator, which indicates that
    126 // it is intended to represent a directory. Returns false otherwise.
    127 // This does NOT check that a directory (or file) actually exists.
    128 bool FilePath::IsDirectory() const 
    129 {
    130 
    131 }
    132 
    133 // Returns true if pathname describes a root directory. (Windows has one
    134 // root directory per disk drive.)
    135 bool FilePath::IsRootDirectory() const 
    136 {
    137 
    138 }
    139 
    140 // Returns true if pathname describes an absolute path.
    141 bool FilePath::IsAbsolutePath() const 
    142 {
    143 
    144 }
    145 
    146 void FilePath::Normalize() 
    147 {
    148 
    149 }
    150 
    151 }  // namespace internal
    152 
    153 }  // namespace testing
    154 
  • 相关阅读:
    SDNU 1416.一元三次方程求解(数学)
    SDNU 1423.入学考试(01背包)
    SDNU 1427.分解质因数(水题)
    SDNU 1429.区间k大数查询(水题)
    1452.接水问题(思维)
    SDNU 1464.最大最小公倍数(思维)
    SDNU 1467.杨辉三角形(水题)
    SDNU 1469.校门外的树(水题)
    SDNU 1474.特殊回文数(水题)
    OC中String与Data之间的转换
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1588923.html
Copyright © 2020-2023  润新知