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  [email protected]
  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  =   3 int  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 

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