现在的位置: 首页 > 综合 > 正文

GCC-3.4.6源代码学习笔记(147)

2013年11月05日 ⁄ 综合 ⁄ 共 10387字 ⁄ 字号 评论关闭



5.13.1.1.2.1.2.         



添加模板方法

下面的隐式转换的机制将尝试查是否能隐式地调用某个模板转换操作符。这个过程不能被命令行选项“
–fimiplicit-template
”所关闭。因为该模板函数是隐式调用的,它不能直接地指定模板实参;该模板实参只能根据调用实参推导。而那些不能推导出来的,将不被选中。

在调用点上,
ctype

是‘
this
’指针的类型,
explicit_targs

是显式模板实参;
arglist

是提供的实参;而
return_type

则是对于转换操作符而言理想的类型(或者对于普通的模板函数,它是
NULL
)。然后
access_path

是访问该函数的类(这里是‘
this
’指针的类型),而
conversion_path

则是定义该函数的类的
binfo

 

2134

static
struct
z_candidate *

2135

add_template_candidate

(struct
z_candidate
**candidates, tree tmpl, tree ctype,    
in
call.c

2136

                     
tree
explicit_targs, tree arglist, tree return_type,

2137

                     
tree
access_path, tree conversion_path, int flags,

2138

                     
unification_kind_t strict)

2139

{

2140

  
return

2141

    
add_template_candidate_real
(candidates, tmpl, ctype,

2142

  
                           
explicit_targs,
arglist, return_type,

2143

  
                           
access_path,
conversion_path,

2144

  
                           
flags, NULL_TREE,
strict);

2145

}

 

另外,在这里
strict

对于普通模板函数是
DEDUCE_CALL
(或者对于转换操作符,则是
DEDUCE_CONV
);并且在下面
add_template_candidate_real


的调用中,把
NULL
传给
obj

 

2035

static
struct
z_candidate*

2036

add_template_candidate_real

(struct
z_candidate
**candidates, tree tmpl,             
in call.c

2037

                         
tree
ctype, tree explicit_targs, tree arglist,

2038

                         
tree
return_type, tree access_path,

2039

                         
tree
conversion_path, int flags, tree obj,

2040

                         
unification_kind_t
strict)

2041

{

2042

  
int ntparms = DECL_NTPARMS
(tmpl);

2043

  
tree targs = make_tree_vec
(ntparms);

2044

  
tree args_without_in_chrg =
arglist;

2045

  
struct
z_candidate *cand;

2046

  
int i;

2047

  
tree fn;

2048

2049

  
/*
We don't do deduction on the in-charge parameter, the VTT

2050

    
parameter or 'this'. 
*/

2051

  
if
(DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl))

2052

    
args_without_in_chrg =
TREE_CHAIN (args_without_in_chrg);

2053

2054

  
if
((DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (tmpl)

2055

       
|| DECL_BASE_CONSTRUCTOR_P
(tmpl))

2056

      
&&
TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (tmpl)))

2057

    
args_without_in_chrg =
TREE_CHAIN (args_without_in_chrg);

2058

2059

  
i = fn_type_unification
(tmpl, explicit_targs,
targs,

2060

                      
args_without_in_chrg,

2061

                      
return_type, strict, -1);

 

在上面,
DECL_NTPARMS
返回
tmpl

的模板形参的个数;相应地,
targs

是保存推导出的实参的
vector
;而
args_without_in_chrg

,由其名字所示,将保存除了那些主管参数(
in-charge
parameter

,即‘
this
’指针,
VTT
等)以外的实参。

5.12.4.1.1.2.2.1.   




模板实参推导

下面给出了【
3
】的条文
clause 14.8.2
“模板实参推导”
[temp.deduct
]



1. 

当一个函数模板特化被引用时,所有的模板实参必须具有值。这些值可以,或者被显式指定,或者在一些情形下,从使用处推导出来。
[
例如:

void f(Array<dcomplex>& cv, Array<int>& ci) {

sort(cv); // call
sort(Array<dcomplex>&)

sort(ci); // call
sort(Array<int>&)

}

void g(double d) {

int i = convert<int>(d); 

// call convert<int,double>(double)

int c = convert<char>(d); 

// call convert<char,double>(double)

}

—例子结束
]

2. 

当指定一个显式模板实参列表时,这些模板实参必须与该模板形参列表兼容,并且必须构成下面所描述的一个有效的函数类型;否则类型推导失败。特别地,当就一个给定的函数模板而言,评估一个显式指定的模板实参列表时,要执行以下步骤:


指定的模板实参必须与模板形参在类型上匹配(也就是,类型,非类型,模板),并且实参个数不能多于形参;否则类型推导失败。


非类型实参必须匹配对应非类型模板形参的类型,或者必须能按
14.3.2
所规定的那样转换到对应非类型形参的类型,否则类型推导失败。


在函数模板具现的函数类型中,所有对对应模板形参的引用为指定的模板实参所代替。如果在一个模板形参的替代中,或在函数模板的函数类型的替代中导致一个无效类型,类型推导失败。
[
注意:异常规范中的等效替代(
equivalent substitution
)仅当该函数具现后才执行,在那一点上,如果替代导致一个无效的类型,程序是非法的
]
。类型推导出于以下原因可能失败:

Ø     


尝试构建一个元素类型是
void
,或一个函数类型,或一个引用类型的数组,或者尝试构建一个大小为
0
或负的数组。
[
例如:

template
<class
T>
int f(T[5]);

int I = f<int>(0);  
// invalid array

int j = f<void>(0); 
// invalid array
]

Ø     


尝试在一个限定名(
qualified name
)中使用一个非类类型。
[
例如:

template
<class
T> int f(typename
T::B*);

int i = f<int>(0); ]

Ø     


尝试使用一个在一个限定名的限定词部分(
qualifier
portion

)中的类型;该限定名命名了一个类型,该类型不包含这个指定的成员,或者该指定的成员不是一个类型,但期望的却是一个类型。
[
例如:

template
<class
T> int f(typename
T::B*);

struct
A {};

struct
C { int B; };

int i = f<A>(0);

int j = f<C>(0); ]

Ø     


尝试为一个引用类型构建指针。

Ø     


尝试为一个引用类型构建引用,或为
void
构建引用。

Ø     


尝试构建“
pointer to member of T
”,当
T
不是一个类类型时。
[
例如:

template
<class
T>
int f(int T::*);

int i = f<int>(0); ]

Ø     


尝试在一个模板实参表达式,或在函数声明中使用的表达式中,执行严格非法的转换。
[
例如:

template
<class
T,
T*> int f(int);

int i2 = f<int,1>(0); 

// can’t conv 1 to int*
]

Ø     


尝试构建一个具有一个
void
类型参数的函数类型。

Ø     


尝试构建一个具有
cv-
限定的函数类型。

3. 

在这个替代执行后,执行在
8.3.5
中描述的函数形参类型调整。
[
例如:一个参数类型“
void () (const
int, int[5])

”变成

void(*)
(int,int*)


] [
注意:在一个函数参数声明中最高层的限定词不会影响该函数类型,但仍然会影响函数内该函数参数变量的类型。—注释结束
] [
例如:

template
<class
T>
void f(T t);

template
<class
X> void g(const
X x);

template
<class
Z> void h(Z, Z*);

int main() {

f<int>(1); 
// #1: function
type is f(int), t is nonconst

f<const
int>(1); 

// #2: function type is f(int), t is const

g<int>(1); 
// #3: function
type is g(int), x is const

g<const
int>(1); 

// #4: function type is g(int), x is const

h<const
int>(1,0); 

// #5: function type is h(int, const int*)

}

—例子结束
] [
注意:
f<int>(1)

f<const
int>(1)

调用不同的函数,尽管这两个被调用的函数具有相同的函数类型。

注释结束
]

4. 

作为结果的替代及调整后的函数类型被用作用于模板实参推导的函数模板的类型。当所有的模板实参被推导出来后,所有在非推导上下文中模板形参的使用,被替代为对应的推导出的实参值。如果该替代导致一个非法类型,如上所描述,类型推导失败。

5. 

除上文所述,一个无效值的使用并不会导致类型推导失败。
[
例如:在下面的例子中
1000
被转换到
signed char
,并且导致一个如(
4.7
)所描述的依赖实现定义的值。换而言之,两个模板都被顾及,虽然
1000
,当被转换到
signed char
时,导致一个依赖实现定义的值。

template
<int>
int f(int);

template
<signed
char> int f(int);

int i1 = f<1>(0); 
// ambiguous

int i2 = f<1000>(0); 
// ambiguous

—例子结束
]

如果模板实参推导成功,下面的函数返回
0

 

8893

int

8894

fn_type_unification

(tree fn,                                                                             
in
pt.c

8895

                 
tree
explicit_targs,

8896

                 
tree targs,

8897

                 
tree args,

8898

                 
tree
return_type,

8899

                 
unification_kind_t
strict,

8900

                 
int len)

8901

{

8902

  
tree parms;

8903

  
tree fntype;

8904

  
int result;

8905

8906

  
my_friendly_assert
(TREE_CODE (fn) == TEMPLATE_DECL, 0);

8907

8908

  
fntype = TREE_TYPE (fn);

8909

  
if (explicit_targs)

8910

  
{

8911

    
/*
[temp.deduct]

8912

  
 

8913

      
The
specified template arguments must match the template

8914

      
parameters in kind (i.e., type, nontype,
template), and there

8915

      
must
not be more arguments than there are parameters;

8916

  
    
otherwise type deduction fails.

8917

8918

      
Nontype arguments must match the types of
the corresponding

8919

      
nontype template parameters, or must be
convertible to the

8920

      
types of the corresponding nontype
parameters as specified in

8921

      
_temp.arg.nontype_, otherwise type
deduction fails.

8922

8923

      
All
references in the function type of the function template

8924

      
to
the corresponding template parameters are replaced by the

8925

      
specified template argument values. If a
substitution in a

8926

      
template parameter or in the function
type of the function

8927

      
template results in an invalid type, type
deduction fails. 
*/

8928

    
int i;

8929

    
tree converted_args;

8930

    
bool incomplete;

8931

8932

    
if (explicit_targs ==
error_mark_node)

8933

      
return
1;

8934

8935

    
converted_args

8936

       
= (coerce_template_parms
(DECL_INNERMOST_TEMPLATE_PARMS
(fn),

8937

                              
explicit_targs,
NULL_TREE, tf_none,

8938

                              
/*require_all_arguments=*/
0));

8939

    
if (converted_args ==
error_mark_node)

8940

      
return
1;

8941

8942

    
/*
Substitute the explicit args into the function type. This is

8943

      
necessary so that, for instance,
explicitly declared function

8944

      
arguments can match null pointed
constants. If we were given

8945

      
an
incomplete set of explicit args, we must not do semantic

8946

     
 
processing during substitution as we could
create partial

8947

      
instantiations. 
*/

8948

    
incomplete = NUM_TMPL_ARGS
(explicit_targs) != NUM_TMPL_ARGS (targs);

8949

    
processing_template_decl

+=
incomplete;

8950

    
fntype = tsubst (fntype,
converted_args, tf_none, NULL_TREE);

8951

    
processing_template_decl

-=
incomplete;

8952

      

8953

    
if (fntype ==
error_mark_node)

8954

      
return
1;

8955

8956

    
/*
Place the explicitly specified arguments in TARGS. 
*/

8957

    
for
(i = NUM_TMPL_ARGS (converted_args); i--;)

8958

      
TREE_VEC_ELT (targs, i)
= TREE_VEC_ELT (converted_args, i);

8959

  
}

 

参数
explicit_args

是显式模板实参,例如,通过一个
template-id
来提供。我们已经在前一节看过了
coerce_template_parms


的一个例子,它转换显式模板实参来匹配形参,而其结果返回给
8935
行的
converted_arg

。那么在
8950
行的
tsubst


用转换后的实参替代模板形参。

 

fn_type_unification (continue)

 

8961

  
parms = TYPE_ARG_TYPES
(fntype);

8962

  
/*
Never do unification on the 'this' parameter. 

*/

8963

  
if
(DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))

8964

    
parms = TREE_CHAIN
(parms);

8965

  

8966

  
if (return_type)

8967

  
{

8968

    
/*
We've been given a return type to match, prepend it. 
*/

8969

    
parms = tree_cons
(NULL_TREE, TREE_TYPE (fntype), parms);

8970

    
args = tree_cons
(NULL_TREE, return_type, args);

8971

    
if (len >= 0)

8972

      
++len;

8973

  
}

8974

8975

 
 
/* We allow incomplete unification without an
error message here

8976

    
because the standard doesn't seem to
explicitly prohibit it. Our

8977

    
callers must be ready to deal with
unification failures in any

8978

    
event. 

*/

8979

  
result = type_unification_real
(DECL_INNERMOST_TEMPLATE_PARMS
(fn),

8980

                           
targs, parms, args, /*subr=*/
0,

8981

                           
strict,
/*allow_incomplete*/
1, len);

8982

8983

  
if (result == 0)

8984

    
/*
All is well so far. Now, check:

8985

       

8986

      
[temp.deduct]

8987

       

8988

      
When
all template arguments have been deduced, all uses of

8989

      
template parameters in nondeduced
contexts are replaced with

8990

      
the
corresponding deduced argument values. If the

8991

      
substitution results in an invalid type,
as described above,

8992

      
type
deduction fails. 
*/

8993

    
if (tsubst (TREE_TYPE
(fn), targs, tf_none, NULL_TREE)

8994

             
==
error_mark_node)

8995

      
return
1;

8996

8997

  
return
result;

8998

}

 

记住现在正在处理函数模板。

在下面的函数中,
tparms

指向模板形参;
targs

是保存将在这里得到的推导后的模板实参的
vector
(它可能是空的,如果给出了显式模板实参。它包含转换后的这些实参);
xparms

是该转换操作符包含返回类型的参数;
xargs

是该转换操作符上的
args_without_in_chrg

(也就是调用时用户使用的实参),加上期望的返回类型;并且如果
subr


1
,表示该函数正在被递归调用(来统一一个函数的实参,或一个函数模板的函数形参);
allow_incomplete


1
;并且
xlen


-1
,表示在成功返回前,考虑所有形参;否则就是
xparms

的长度,并考虑这些实参。

 

9113

static
int

9114

type_unification_real

(tree tparms,                                                                    
in
pt.c

9115

               
   
tree targs,

9116

                  
tree xparms,

9117

                  
tree xargs,

9118

                  
int subr,

9119

                  
unification_kind_t strict,

9120

                  
int
allow_incomplete,

9121

                  
int xlen)

9122

{

9123

  
tree parm, arg;

9124

  
int i;

9125

  
int ntparms =
TREE_VEC_LENGTH (tparms);

9126

  
int sub_strict;

9127

  
int saw_undeduced = 0;

9128

  
tree parms, args;

9129

  
int len;

9130

9131

  
my_friendly_assert
(TREE_CODE (tparms) == TREE_VEC, 289);

9132

  
my_friendly_assert (xparms
== NULL_TREE

9133

                   
||
TREE_CODE (xparms) == TREE_LIST, 290);

9134

  
my_friendly_assert (!xargs
|| TREE_CODE (xargs) == TREE_LIST, 291);

9135

  
my_friendly_assert (ntparms
> 0, 292);

9136

9137

  
switch
(strict)

9138

  
{

9139

    
case
DEDUCE_CALL:

9140

      
sub_strict = (UNIFY_ALLOW_OUTER_LEVEL |
UNIFY_ALLOW_MORE_CV_QUAL

9141

                 
|
UNIFY_ALLOW_DERIVED);

9142

      
break
;

9143

      

9144

    
case
DEDUCE_CONV:

9145

      
sub_strict =
UNIFY_ALLOW_LESS_CV_QUAL;

9146

      
break
;

9147

9148

    
case
DEDUCE_EXACT:

9149

      
sub_strict =
UNIFY_ALLOW_NONE;

9150

      
break
;

9151

    

9152

    
case
DEDUCE_ORDER:

9153

      
sub_strict =
UNIFY_ALLOW_NONE;

9154

      
break
;

9155

      

9156

    
default
:

9157

      
abort ();

9158

  
}

9159

抱歉!评论已关闭.