DimensionedFieldFunctionsM.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 
28 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29 
30 #define UNARY_FUNCTION(ReturnType, Type1, Func, Dfunc) \
31  \
32 TEMPLATE \
33 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
34 ( \
35  const DimensionedField<Type1, GeoMesh>& df1 \
36 ) \
37 { \
38  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
39  ( \
40  new DimensionedField<ReturnType, GeoMesh> \
41  ( \
42  IOobject \
43  ( \
44  #Func "(" + df1.name() + ')', \
45  df1.instance(), \
46  df1.db() \
47  ), \
48  df1.mesh(), \
49  Dfunc(df1.dimensions()) \
50  ) \
51  ); \
52  \
53  Func(tRes().field(), df1.field()); \
54  \
55  return tRes; \
56 } \
57  \
58 TEMPLATE \
59 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
60 ( \
61  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1 \
62 ) \
63 { \
64  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
65  \
66  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
67  ( \
68  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
69  ( \
70  tdf1, \
71  #Func "(" + df1.name() + ')', \
72  Dfunc(df1.dimensions()) \
73  ) \
74  ); \
75  \
76  Func(tRes().field(), df1.field()); \
77  \
78  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
79  \
80  return tRes; \
81 }
82 
83 
84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
85 
86 #define UNARY_OPERATOR(ReturnType, Type1, Op, OpFunc, Dfunc) \
87  \
88 TEMPLATE \
89 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
90 ( \
91  const DimensionedField<Type1, GeoMesh>& df1 \
92 ) \
93 { \
94  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
95  ( \
96  new DimensionedField<ReturnType, GeoMesh> \
97  ( \
98  IOobject \
99  ( \
100  #Op + df1.name(), \
101  df1.instance(), \
102  df1.db() \
103  ), \
104  df1.mesh(), \
105  Dfunc(df1.dimensions()) \
106  ) \
107  ); \
108  \
109  Foam::OpFunc(tRes().field(), df1.field()); \
110  \
111  return tRes; \
112 } \
113  \
114 TEMPLATE \
115 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
116 ( \
117  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1 \
118 ) \
119 { \
120  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
121  \
122  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
123  ( \
124  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
125  ( \
126  tdf1, \
127  #Op + df1.name(), \
128  Dfunc(df1.dimensions()) \
129  ) \
130  ); \
131  \
132  Foam::OpFunc(tRes().field(), df1.field()); \
133  \
134  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
135  \
136  return tRes; \
137 }
138 
139 
140 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
141 
142 #define BINARY_FUNCTION(ReturnType, Type1, Type2, Func) \
143  \
144 TEMPLATE \
145 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
146 ( \
147  const DimensionedField<Type1, GeoMesh>& df1, \
148  const DimensionedField<Type2, GeoMesh>& df2 \
149 ) \
150 { \
151  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
152  ( \
153  new DimensionedField<ReturnType, GeoMesh> \
154  ( \
155  IOobject \
156  ( \
157  #Func "(" + df1.name() + ',' + df2.name() + ')', \
158  df1.instance(), \
159  df1.db() \
160  ), \
161  df1.mesh(), \
162  Func(df1.dimensions(), df2.dimensions()) \
163  ) \
164  ); \
165  \
166  Func(tRes().field(), df1.field(), df2.field()); \
167  \
168  return tRes; \
169 } \
170  \
171 TEMPLATE \
172 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
173 ( \
174  const DimensionedField<Type1, GeoMesh>& df1, \
175  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
176 ) \
177 { \
178  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
179  \
180  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
181  ( \
182  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::New \
183  ( \
184  tdf2, \
185  #Func "(" + df1.name() + ',' + df2.name() + ')', \
186  Func(df1.dimensions(), df2.dimensions()) \
187  ) \
188  ); \
189  \
190  Func(tRes().field(), df1.field(), df2.field()); \
191  \
192  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::clear(tdf2); \
193  \
194  return tRes; \
195 } \
196  \
197 TEMPLATE \
198 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
199 ( \
200  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
201  const DimensionedField<Type2, GeoMesh>& df2 \
202 ) \
203 { \
204  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
205  \
206  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
207  ( \
208  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
209  ( \
210  tdf1, \
211  #Func "(" + df1.name() + ',' + df2.name() + ')', \
212  Func(df1.dimensions(), df2.dimensions()) \
213  ) \
214  ); \
215  \
216  Func(tRes().field(), df1.field(), df2.field()); \
217  \
218  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
219  \
220  return tRes; \
221 } \
222  \
223 TEMPLATE \
224 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
225 ( \
226  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
227  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
228 ) \
229 { \
230  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
231  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
232  \
233  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
234  ( \
235  reuseTmpTmpDimensionedField \
236  <ReturnType, Type1, Type1, Type2, GeoMesh>::New \
237  ( \
238  tdf1, \
239  tdf2, \
240  #Func "(" + df1.name() + ',' + df2.name() + ')', \
241  Func(df1.dimensions(), df2.dimensions()) \
242  ) \
243  ); \
244  \
245  Func(tRes().field(), df1.field(), df2.field()); \
246  \
247  reuseTmpTmpDimensionedField<ReturnType, Type1, Type1, Type2, GeoMesh> \
248  ::clear(tdf1, tdf2); \
249  \
250  return tRes; \
251 }
252 
253 
254 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
255 
256 #define BINARY_TYPE_FUNCTION_SF(ReturnType, Type1, Type2, Func) \
257  \
258 TEMPLATE \
259 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
260 ( \
261  const dimensioned<Type1>& dt1, \
262  const DimensionedField<Type2, GeoMesh>& df2 \
263 ) \
264 { \
265  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
266  ( \
267  new DimensionedField<ReturnType, GeoMesh> \
268  ( \
269  IOobject \
270  ( \
271  #Func "(" + dt1.name() + ',' + df2.name() + ')', \
272  df2.instance(), \
273  df2.db() \
274  ), \
275  df2.mesh(), \
276  Func(dt1.dimensions(), df2.dimensions()) \
277  ) \
278  ); \
279  \
280  Func(tRes().field(), dt1.value(), df2.field()); \
281  \
282  return tRes; \
283 } \
284  \
285 TEMPLATE \
286 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
287 ( \
288  const Type1& t1, \
289  const DimensionedField<Type2, GeoMesh>& df2 \
290 ) \
291 { \
292  return Func(dimensioned<Type1>(t1), df2); \
293 } \
294  \
295  \
296 TEMPLATE \
297 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
298 ( \
299  const dimensioned<Type1>& dt1, \
300  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
301 ) \
302 { \
303  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
304  \
305  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
306  ( \
307  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::New \
308  ( \
309  tdf2, \
310  #Func "(" + dt1.name() + ',' + df2.name() + ')', \
311  Func(dt1.dimensions(), df2.dimensions()) \
312  ) \
313  ); \
314  \
315  Func(tRes().field(), dt1.value(), df2.field()); \
316  \
317  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::clear(tdf2); \
318  \
319  return tRes; \
320 } \
321  \
322 TEMPLATE \
323 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
324 ( \
325  const Type1& t1, \
326  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
327 ) \
328 { \
329  return Func(dimensioned<Type2>(t1), tdf2); \
330 }
331 
332 
333 #define BINARY_TYPE_FUNCTION_FS(ReturnType, Type1, Type2, Func) \
334  \
335 TEMPLATE \
336 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
337 ( \
338  const DimensionedField<Type1, GeoMesh>& df1, \
339  const dimensioned<Type2>& dt2 \
340 ) \
341 { \
342  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
343  ( \
344  new DimensionedField<ReturnType, GeoMesh> \
345  ( \
346  IOobject \
347  ( \
348  #Func "(" + df1.name() + ',' + dt2.name() + ')', \
349  df1.instance(), \
350  df1.db() \
351  ), \
352  df1.mesh(), \
353  Func(df1.dimensions(), dt2.dimensions()) \
354  ) \
355  ); \
356  \
357  Func(tRes().field(), df1.field(), dt2.value()); \
358  \
359  return tRes; \
360 } \
361  \
362 TEMPLATE \
363 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
364 ( \
365  const DimensionedField<Type1, GeoMesh>& df1, \
366  const Type2& t2 \
367 ) \
368 { \
369  return Func(df1, dimensioned<Type2>(t2)); \
370 } \
371  \
372  \
373 TEMPLATE \
374 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
375 ( \
376  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
377  const dimensioned<Type2>& dt2 \
378 ) \
379 { \
380  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
381  \
382  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
383  ( \
384  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
385  ( \
386  tdf1, \
387  #Func "(" + df1.name() + ',' + dt2.name() + ')', \
388  Func(df1.dimensions(), dt2.dimensions()) \
389  ) \
390  ); \
391  \
392  Func(tRes().field(), df1.field(), dt2.value()); \
393  \
394  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
395  \
396  return tRes; \
397 } \
398  \
399 TEMPLATE \
400 tmp<DimensionedField<ReturnType, GeoMesh> > Func \
401 ( \
402  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
403  const Type2& t2 \
404 ) \
405 { \
406  return Func(tdf1, dimensioned<Type2>(t2)); \
407 }
408 
409 
410 #define BINARY_TYPE_FUNCTION(ReturnType, Type1, Type2, Func) \
411  BINARY_TYPE_FUNCTION_SF(ReturnType, Type1, Type2, Func) \
412  BINARY_TYPE_FUNCTION_FS(ReturnType, Type1, Type2, Func)
413 
414 
415 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
416 
417 #define BINARY_OPERATOR(ReturnType, Type1, Type2, Op, OpName, OpFunc) \
418  \
419 TEMPLATE \
420 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
421 ( \
422  const DimensionedField<Type1, GeoMesh>& df1, \
423  const DimensionedField<Type2, GeoMesh>& df2 \
424 ) \
425 { \
426  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
427  ( \
428  new DimensionedField<ReturnType, GeoMesh> \
429  ( \
430  IOobject \
431  ( \
432  '(' + df1.name() + OpName + df2.name() + ')', \
433  df1.instance(), \
434  df1.db() \
435  ), \
436  df1.mesh(), \
437  df1.dimensions() Op df2.dimensions() \
438  ) \
439  ); \
440  \
441  Foam::OpFunc(tRes().field(), df1.field(), df2.field()); \
442  \
443  return tRes; \
444 } \
445  \
446 TEMPLATE \
447 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
448 ( \
449  const DimensionedField<Type1, GeoMesh>& df1, \
450  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
451 ) \
452 { \
453  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
454  \
455  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
456  ( \
457  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::New \
458  ( \
459  tdf2, \
460  '(' + df1.name() + OpName + df2.name() + ')', \
461  df1.dimensions() Op df2.dimensions() \
462  ) \
463  ); \
464  \
465  Foam::OpFunc(tRes().field(), df1.field(), df2.field()); \
466  \
467  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::clear(tdf2); \
468  \
469  return tRes; \
470 } \
471  \
472 TEMPLATE \
473 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
474 ( \
475  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
476  const DimensionedField<Type2, GeoMesh>& df2 \
477 ) \
478 { \
479  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
480  \
481  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
482  ( \
483  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
484  ( \
485  tdf1, \
486  '(' + df1.name() + OpName + df2.name() + ')', \
487  df1.dimensions() Op df2.dimensions() \
488  ) \
489  ); \
490  \
491  Foam::OpFunc(tRes().field(), df1.field(), df2.field()); \
492  \
493  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
494  \
495  return tRes; \
496 } \
497  \
498 TEMPLATE \
499 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
500 ( \
501  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
502  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
503 ) \
504 { \
505  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
506  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
507  \
508  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
509  ( \
510  reuseTmpTmpDimensionedField \
511  <ReturnType, Type1, Type1, Type2, GeoMesh>::New \
512  ( \
513  tdf1, \
514  tdf2, \
515  '(' + df1.name() + OpName + df2.name() + ')', \
516  df1.dimensions() Op df2.dimensions() \
517  ) \
518  ); \
519  \
520  Foam::OpFunc(tRes().field(), df1.field(), df2.field()); \
521  \
522  reuseTmpTmpDimensionedField<ReturnType, Type1, Type1, Type2, GeoMesh>:: \
523  clear(tdf1, tdf2); \
524  \
525  return tRes; \
526 }
527 
528 
529 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
530 
531 #define BINARY_TYPE_OPERATOR_SF(ReturnType, Type1, Type2, Op, OpName, OpFunc) \
532  \
533 TEMPLATE \
534 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
535 ( \
536  const dimensioned<Type1>& dt1, \
537  const DimensionedField<Type2, GeoMesh>& df2 \
538 ) \
539 { \
540  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
541  ( \
542  new DimensionedField<ReturnType, GeoMesh> \
543  ( \
544  IOobject \
545  ( \
546  '(' + dt1.name() + OpName + df2.name() + ')', \
547  df2.instance(), \
548  df2.db() \
549  ), \
550  df2.mesh(), \
551  dt1.dimensions() Op df2.dimensions() \
552  ) \
553  ); \
554  \
555  Foam::OpFunc(tRes().field(), dt1.value(), df2.field()); \
556  \
557  return tRes; \
558 } \
559  \
560 TEMPLATE \
561 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
562 ( \
563  const Type1& t1, \
564  const DimensionedField<Type2, GeoMesh>& df2 \
565 ) \
566 { \
567  return dimensioned<Type1>(t1) Op df2; \
568 } \
569  \
570  \
571 TEMPLATE \
572 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
573 ( \
574  const dimensioned<Type1>& dt1, \
575  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
576 ) \
577 { \
578  const DimensionedField<Type2, GeoMesh>& df2 = tdf2(); \
579  \
580  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
581  ( \
582  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::New \
583  ( \
584  tdf2, \
585  '(' + dt1.name() + OpName + df2.name() + ')', \
586  dt1.dimensions() Op df2.dimensions() \
587  ) \
588  ); \
589  \
590  Foam::OpFunc(tRes().field(), dt1.value(), tdf2().field()); \
591  \
592  reuseTmpDimensionedField<ReturnType, Type2, GeoMesh>::clear(tdf2); \
593  \
594  return tRes; \
595 } \
596  \
597 TEMPLATE \
598 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
599 ( \
600  const Type1& t1, \
601  const tmp<DimensionedField<Type2, GeoMesh> >& tdf2 \
602 ) \
603 { \
604  return dimensioned<Type1>(t1) Op tdf2; \
605 }
606 
607 
608 #define BINARY_TYPE_OPERATOR_FS(ReturnType, Type1, Type2, Op, OpName, OpFunc) \
609  \
610 TEMPLATE \
611 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
612 ( \
613  const DimensionedField<Type1, GeoMesh>& df1, \
614  const dimensioned<Type2>& dt2 \
615 ) \
616 { \
617  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
618  ( \
619  new DimensionedField<ReturnType, GeoMesh> \
620  ( \
621  IOobject \
622  ( \
623  '(' + df1.name() + OpName + dt2.name() + ')', \
624  df1.instance(), \
625  df1.db() \
626  ), \
627  df1.mesh(), \
628  df1.dimensions() Op dt2.dimensions() \
629  ) \
630  ); \
631  \
632  Foam::OpFunc(tRes().field(), df1.field(), dt2.value()); \
633  \
634  return tRes; \
635 } \
636  \
637 TEMPLATE \
638 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
639 ( \
640  const DimensionedField<Type1, GeoMesh>& df1, \
641  const Type2& t2 \
642 ) \
643 { \
644  return df1 Op dimensioned<Type2>(t2); \
645 } \
646  \
647  \
648 TEMPLATE \
649 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
650 ( \
651  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
652  const dimensioned<Type2>& dt2 \
653 ) \
654 { \
655  const DimensionedField<Type1, GeoMesh>& df1 = tdf1(); \
656  \
657  tmp<DimensionedField<ReturnType, GeoMesh> > tRes \
658  ( \
659  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::New \
660  ( \
661  tdf1, \
662  '(' + df1.name() + OpName + dt2.name() + ')', \
663  df1.dimensions() Op dt2.dimensions() \
664  ) \
665  ); \
666  \
667  Foam::OpFunc(tRes().field(), tdf1().field(), dt2.value()); \
668  \
669  reuseTmpDimensionedField<ReturnType, Type1, GeoMesh>::clear(tdf1); \
670  \
671  return tRes; \
672 } \
673  \
674 TEMPLATE \
675 tmp<DimensionedField<ReturnType, GeoMesh> > operator Op \
676 ( \
677  const tmp<DimensionedField<Type1, GeoMesh> >& tdf1, \
678  const Type2& t2 \
679 ) \
680 { \
681  return tdf1 Op dimensioned<Type2>(t2); \
682 }
683 
684 #define BINARY_TYPE_OPERATOR(ReturnType, Type1, Type2, Op, OpName, OpFunc) \
685  BINARY_TYPE_OPERATOR_SF(ReturnType, Type1, Type2, Op, OpName, OpFunc) \
686  BINARY_TYPE_OPERATOR_FS(ReturnType, Type1, Type2, Op, OpName, OpFunc)
687 
688 
689 // ************************************************************************* //