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 
posted @ 2009-10-23 22:45  阁子  阅读(5552)  评论(4编辑  收藏  举报