Commit 104bf76a by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (most_specialized_instantiation): New function.

	* cp-tree.h (most_specialized_instantiation): New function.
	(print_candidates): Likewise.
	* class.c (validate_lhs): Remove.
	(resolve_address_of_overloaded_function): New function, split out
	and then substantially reworked, from ...
	(instantiate_type): Use it.  Simplify.
	* cvt.c (convert_to_reference): Complain when caller has indicated
	that's the right thing to do.  Don't crash if instantiate_type
	fails.
	* pt.c: Substitute `parameters' for `paramters' throughout.
	(print_candidates): Don't make it static.
	(most_specialized_instantiation): Split out from ...
	(most_specialized): Here.

From-SVN: r24225
parent f8976021
1998-12-09 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (most_specialized_instantiation): New function.
(print_candidates): Likewise.
* class.c (validate_lhs): Remove.
(resolve_address_of_overloaded_function): New function, split out
and then substantially reworked, from ...
(instantiate_type): Use it. Simplify.
* cvt.c (convert_to_reference): Complain when caller has indicated
that's the right thing to do. Don't crash if instantiate_type
fails.
* pt.c: Substitute `parameters' for `paramters' throughout.
(print_candidates): Don't make it static.
(most_specialized_instantiation): Split out from ...
(most_specialized): Here.
Wed Dec 9 15:33:01 1998 Dave Brolley <brolley@cygnus.com> Wed Dec 9 15:33:01 1998 Dave Brolley <brolley@cygnus.com>
* lex.c (lang_init_options): Initialize cpplib. * lex.c (lang_init_options): Initialize cpplib.
......
...@@ -4971,27 +4971,245 @@ pop_lang_context () ...@@ -4971,27 +4971,245 @@ pop_lang_context ()
/* Type instantiation routines. */ /* Type instantiation routines. */
/* Given an OVERLOAD and a TARGET_TYPE, return the function that
matches the TARGET_TYPE. If there is no satisfactory match, return
error_mark_node, and issue an error message if COMPLAIN is
non-zero. If TEMPLATE_ONLY, the name of the overloaded function
was a template-id, and EXPLICIT_TARGS are the explicitly provided
template arguments. */
static tree static tree
validate_lhs (lhstype, complain) resolve_address_of_overloaded_function (target_type,
tree lhstype; overload,
complain,
template_only,
explicit_targs)
tree target_type;
tree overload;
int complain; int complain;
int template_only;
tree explicit_targs;
{ {
if (TYPE_PTRMEMFUNC_P (lhstype)) /* Here's what the standard says:
lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
[over.over]
If the name is a function template, template argument deduction
is done, and if the argument deduction succeeds, the deduced
arguments are used to generate a single template function, which
is added to the set of overloaded functions considered.
Non-member functions and static member functions match targets of
type "pointer-to-function" or "reference-to-function." Nonstatic
member functions match targets of type "pointer-to-member
function;" the function type of the pointer to member is used to
select the member function from the set of overloaded member
functions. If a nonstatic member function is selected, the
reference to the overloaded function name is required to have the
form of a pointer to member as described in 5.3.1.
If more than one function is selected, any template functions in
the set are eliminated if the set also contains a non-template
function, and any given template function is eliminated if the
set contains a second template function that is more specialized
than the first according to the partial ordering rules 14.5.5.2.
After such eliminations, if any, there shall remain exactly one
selected function. */
int is_ptrmem = 0;
int is_reference = 0;
/* We store the matches in a TREE_LIST rooted here. The functions
are the TREE_PURPOSE, not the TREE_VALUE, in this list, for easy
interoperability with most_specialized_instantiation. */
tree matches = NULL_TREE;
/* If the TARGET_TYPE is a pointer-to-a-method, we convert it to
proper pointer-to-member type here. */
if (TREE_CODE (target_type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (target_type)) == METHOD_TYPE)
target_type = build_ptrmemfunc_type (target_type);
/* Check that the TARGET_TYPE is reasonable. */
if (TYPE_PTRFN_P (target_type))
/* This is OK. */
;
else if (TYPE_PTRMEMFUNC_P (target_type))
/* This is OK, too. */
is_ptrmem = 1;
else if (TREE_CODE (target_type) == FUNCTION_TYPE)
{
/* This is OK, too. This comes from a conversion to reference
type. */
target_type = build_reference_type (target_type);
is_reference = 1;
}
else
{
if (complain)
cp_error("cannot resolve overloaded function `%D' based on conversion to type `%T'",
DECL_NAME (OVL_FUNCTION (overload)), target_type);
return error_mark_node;
}
/* If we can find a non-template function that matches, we can just
use it. There's no point in generating template instantiations
if we're just going to throw them out anyhow. But, of course, we
can only do this when we don't *need* a template function. */
if (!template_only)
{
tree fns;
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
tree fntype;
if (TREE_CODE (lhstype) == POINTER_TYPE) if (TREE_CODE (fn) == TEMPLATE_DECL)
/* We're not looking for templates just yet. */
continue;
if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
!= is_ptrmem)
/* We're looking for a non-static member, and this isn't
one, or vice versa. */
continue;
/* See if there's a match. */
fntype = TREE_TYPE (fn);
if (is_ptrmem)
fntype = build_ptrmemfunc_type (build_pointer_type (fntype));
else if (!is_reference)
fntype = build_pointer_type (fntype);
if (can_convert_arg (target_type, fntype, fn))
matches = scratch_tree_cons (fn, NULL_TREE, matches);
}
}
/* Now, if we've already got a match (or matches), there's no need
to proceed to the template functions. But, if we don't have a
match we need to look at them, too. */
if (!matches)
{ {
if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE tree target_fn_type;
|| TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE) tree target_arg_types;
lhstype = TREE_TYPE (lhstype); tree fns;
if (is_ptrmem)
{
target_fn_type
= TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (target_type));
target_arg_types = TREE_CHAIN (TYPE_ARG_TYPES (target_fn_type));
}
else else
{ {
if (complain) target_fn_type = TREE_TYPE (target_type);
error ("invalid type combination for overload"); target_arg_types = TYPE_ARG_TYPES (target_fn_type);
return error_mark_node; }
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
tree fn_arg_types;
tree instantiation;
tree instantiation_type;
tree targs;
if (TREE_CODE (fn) != TEMPLATE_DECL)
/* We're only looking for templates. */
continue;
if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
!= is_ptrmem)
/* We're looking for a non-static member, and this isn't
one, or vice versa. */
continue;
/* We don't use the `this' argument to do argument deduction
since that would prevent us from converting a base class
pointer-to-member to a derived class pointer-to-member. */
fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
if (is_ptrmem)
fn_arg_types = TREE_CHAIN (fn_arg_types);
/* Try to do argument deduction. */
targs = make_scratch_vec (DECL_NTPARMS (fn));
if (type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
targs,
fn_arg_types,
target_arg_types,
explicit_targs,
DEDUCE_EXACT,
/*allow_incomplete=*/1) != 0)
/* Argument deduction failed. */
continue;
/* Instantiate the template. */
instantiation = instantiate_template (fn, targs);
if (instantiation == error_mark_node)
/* Instantiation failed. */
continue;
/* See if there's a match. */
instantiation_type = TREE_TYPE (instantiation);
if (is_ptrmem)
instantiation_type =
build_ptrmemfunc_type (build_pointer_type (instantiation_type));
else if (!is_reference)
instantiation_type = build_pointer_type (instantiation_type);
if (can_convert_arg (target_type, instantiation_type, instantiation))
matches = scratch_tree_cons (instantiation, fn, matches);
}
/* Now, remove all but the most specialized of the matches. */
if (matches)
{
tree match = most_specialized_instantiation (matches,
explicit_targs);
if (match != error_mark_node)
matches = scratch_tree_cons (match, NULL_TREE, NULL_TREE);
}
}
/* Now we should have exactly one function in MATCHES. */
if (matches == NULL_TREE)
{
/* There were *no* matches. */
if (complain)
{
cp_error ("cannot convert overloaded function `%D' to type `%#T'",
DECL_NAME (OVL_FUNCTION (overload)),
target_type);
cp_error ("because no suitable overload exists");
}
return error_mark_node;
}
else if (TREE_CHAIN (matches))
{
/* There were too many matches. */
if (complain)
{
tree match;
cp_error ("converting overloaded function `%D' to type `%#T' is ambiguous",
DECL_NAME (OVL_FUNCTION (overload)),
target_type);
/* Since print_candidates expects the functions in the
TREE_VALUE slot, we flip them here. */
for (match = matches; match; match = TREE_CHAIN (match))
TREE_VALUE (match) = TREE_PURPOSE (match);
print_candidates (matches);
} }
return error_mark_node;
} }
return lhstype;
/* Good, exactly one match. */
return TREE_PURPOSE (matches);
} }
/* This function will instantiate the type of the expression given in /* This function will instantiate the type of the expression given in
...@@ -5009,9 +5227,6 @@ instantiate_type (lhstype, rhs, complain) ...@@ -5009,9 +5227,6 @@ instantiate_type (lhstype, rhs, complain)
tree lhstype, rhs; tree lhstype, rhs;
int complain; int complain;
{ {
tree explicit_targs = NULL_TREE;
int template_only = 0;
if (TREE_CODE (lhstype) == UNKNOWN_TYPE) if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
{ {
if (complain) if (complain)
...@@ -5109,141 +5324,20 @@ instantiate_type (lhstype, rhs, complain) ...@@ -5109,141 +5324,20 @@ instantiate_type (lhstype, rhs, complain)
/* Fall through. */ /* Fall through. */
case TEMPLATE_ID_EXPR: case TEMPLATE_ID_EXPR:
{ return
explicit_targs = TREE_OPERAND (rhs, 1); resolve_address_of_overloaded_function (lhstype,
template_only = 1; TREE_OPERAND (rhs, 0),
rhs = TREE_OPERAND (rhs, 0); complain,
} /*template_only=*/1,
/* fall through */ TREE_OPERAND (rhs, 1));
my_friendly_assert (TREE_CODE (rhs) == OVERLOAD, 980401);
case OVERLOAD: case OVERLOAD:
{ return
tree elem, elems; resolve_address_of_overloaded_function (lhstype,
rhs,
/* Check that the LHSTYPE and the RHS are reasonable. */ complain,
lhstype = validate_lhs (lhstype, complain); /*template_only=*/0,
if (lhstype == error_mark_node) /*explicit_targs=*/NULL_TREE);
return lhstype;
if (TREE_CODE (lhstype) != FUNCTION_TYPE
&& TREE_CODE (lhstype) != METHOD_TYPE)
{
if (complain)
cp_error("cannot resolve overloaded function `%D' "
"based on non-function type `%T'",
DECL_NAME (OVL_FUNCTION (rhs)), lhstype);
return error_mark_node;
}
/* Look for an exact match, by searching through the
overloaded functions. */
if (template_only)
/* If we're processing a template-id, only a template
function can match, so we don't look through the
overloaded functions. */
;
else for (elems = rhs; elems; elems = OVL_CHAIN (elems))
{
elem = OVL_FUNCTION (elems);
if (TREE_CODE (elem) == FUNCTION_DECL
&& same_type_p (lhstype, TREE_TYPE (elem)))
{
mark_used (elem);
return elem;
}
}
/* No overloaded function was an exact match. See if we can
instantiate some template to match. */
{
tree save_elem = 0;
elems = rhs;
if (TREE_CODE (elems) == TREE_LIST)
elems = TREE_VALUE (rhs);
for (; elems; elems = OVL_NEXT (elems))
if (TREE_CODE (elem = OVL_CURRENT (elems)) == TEMPLATE_DECL)
{
int n = DECL_NTPARMS (elem);
tree t = make_scratch_vec (n);
int i;
i = type_unification
(DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
TYPE_ARG_TYPES (TREE_TYPE (elem)),
TYPE_ARG_TYPES (lhstype), explicit_targs, DEDUCE_EXACT, 1);
if (i == 0)
{
if (save_elem)
{
cp_error ("ambiguous template instantiation converting to `%#T'", lhstype);
return error_mark_node;
}
save_elem = instantiate_template (elem, t);
/* Check the return type. */
if (!same_type_p (TREE_TYPE (lhstype),
TREE_TYPE (TREE_TYPE (save_elem))))
save_elem = 0;
}
}
if (save_elem)
{
mark_used (save_elem);
return save_elem;
}
}
/* There's no exact match, and no templates can be
instantiated to match. The last thing we try is to see if
some ordinary overloaded function is close enough. If
we're only looking for template functions, we don't do
this. */
if (!template_only)
{
for (elems = rhs; elems; elems = OVL_NEXT (elems))
{
elem = OVL_CURRENT (elems);
if (TREE_CODE (elem) == FUNCTION_DECL
&& comp_target_types (lhstype, TREE_TYPE (elem), 1) > 0)
break;
}
if (elems)
{
tree save_elem = elem;
for (elems = OVL_CHAIN (elems); elems;
elems = OVL_CHAIN (elems))
{
elem = OVL_FUNCTION (elems);
if (TREE_CODE (elem) == FUNCTION_DECL
&& comp_target_types (lhstype, TREE_TYPE (elem), 0) >0)
break;
}
if (elems)
{
if (complain)
{
cp_error
("cannot resolve overload to target type `%#T'",
lhstype);
cp_error_at (" ambiguity between `%#D'", save_elem);
cp_error_at (" and `%#D', at least", elem);
}
return error_mark_node;
}
mark_used (save_elem);
return save_elem;
}
}
/* We failed to find a match. */
if (complain)
{
cp_error ("cannot resolve overload to target type `%#T'", lhstype);
cp_error
(" because no suitable overload of function `%D' exists",
DECL_NAME (OVL_FUNCTION (rhs)));
}
return error_mark_node;
}
case TREE_LIST: case TREE_LIST:
{ {
...@@ -5370,16 +5464,8 @@ instantiate_type (lhstype, rhs, complain) ...@@ -5370,16 +5464,8 @@ instantiate_type (lhstype, rhs, complain)
return rhs; return rhs;
case ADDR_EXPR: case ADDR_EXPR:
if (TYPE_PTRMEMFUNC_P (lhstype))
lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
else if (TREE_CODE (lhstype) != POINTER_TYPE)
{
if (complain)
error ("type for resolving address of overloaded function must be pointer type");
return error_mark_node;
}
{ {
tree fn = instantiate_type (TREE_TYPE (lhstype), TREE_OPERAND (rhs, 0), complain); tree fn = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
if (fn == error_mark_node) if (fn == error_mark_node)
return error_mark_node; return error_mark_node;
mark_addressable (fn); mark_addressable (fn);
......
...@@ -3030,6 +3030,8 @@ extern int is_specialization_of PROTO((tree, tree)); ...@@ -3030,6 +3030,8 @@ extern int is_specialization_of PROTO((tree, tree));
extern int comp_template_args PROTO((tree, tree)); extern int comp_template_args PROTO((tree, tree));
extern void maybe_process_partial_specialization PROTO((tree)); extern void maybe_process_partial_specialization PROTO((tree));
extern void maybe_check_template_type PROTO((tree)); extern void maybe_check_template_type PROTO((tree));
extern tree most_specialized_instantiation PROTO((tree, tree));
extern void print_candidates PROTO((tree));
extern int processing_specialization; extern int processing_specialization;
extern int processing_explicit_instantiation; extern int processing_explicit_instantiation;
......
...@@ -414,7 +414,11 @@ convert_to_reference (reftype, expr, convtype, flags, decl) ...@@ -414,7 +414,11 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
if (TREE_CODE (type) == FUNCTION_TYPE && intype == unknown_type_node) if (TREE_CODE (type) == FUNCTION_TYPE && intype == unknown_type_node)
{ {
expr = instantiate_type (type, expr, 0); expr = instantiate_type (type, expr,
(flags & LOOKUP_COMPLAIN) != 0);
if (expr == error_mark_node)
return error_mark_node;
intype = TREE_TYPE (expr); intype = TREE_TYPE (expr);
} }
......
...@@ -112,7 +112,6 @@ static void push_inline_template_parms_recursive PROTO((tree, int)); ...@@ -112,7 +112,6 @@ static void push_inline_template_parms_recursive PROTO((tree, int));
static tree retrieve_specialization PROTO((tree, tree)); static tree retrieve_specialization PROTO((tree, tree));
static tree register_specialization PROTO((tree, tree, tree)); static tree register_specialization PROTO((tree, tree, tree));
static int unregister_specialization PROTO((tree, tree)); static int unregister_specialization PROTO((tree, tree));
static void print_candidates PROTO((tree));
static tree reduce_template_parm_level PROTO((tree, tree, int)); static tree reduce_template_parm_level PROTO((tree, tree, int));
static tree build_template_decl PROTO((tree, tree)); static tree build_template_decl PROTO((tree, tree));
static int mark_template_parm PROTO((tree, void *)); static int mark_template_parm PROTO((tree, void *));
...@@ -883,7 +882,7 @@ unregister_specialization (spec, tmpl) ...@@ -883,7 +882,7 @@ unregister_specialization (spec, tmpl)
/* Print the list of candidate FNS in an error message. */ /* Print the list of candidate FNS in an error message. */
static void void
print_candidates (fns) print_candidates (fns)
tree fns; tree fns;
{ {
...@@ -1996,7 +1995,7 @@ process_partial_specialization (decl) ...@@ -1996,7 +1995,7 @@ process_partial_specialization (decl)
/* We haven't yet initialized TPD2. Do so now. */ /* We haven't yet initialized TPD2. Do so now. */
tpd2.arg_uses_template_parms tpd2.arg_uses_template_parms
= (int*) alloca (sizeof (int) * nargs); = (int*) alloca (sizeof (int) * nargs);
/* The number of paramters here is the number in the /* The number of parameters here is the number in the
main template, which, as checked in the assertion main template, which, as checked in the assertion
above, is NARGS. */ above, is NARGS. */
tpd2.parms = (int*) alloca (sizeof (int) * nargs); tpd2.parms = (int*) alloca (sizeof (int) * nargs);
...@@ -2004,7 +2003,7 @@ process_partial_specialization (decl) ...@@ -2004,7 +2003,7 @@ process_partial_specialization (decl)
TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl)); TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
} }
/* Mark the template paramters. But this time, we're /* Mark the template parameters. But this time, we're
looking for the template parameters of the main looking for the template parameters of the main
template, not in the specialization. */ template, not in the specialization. */
tpd2.current_arg = i; tpd2.current_arg = i;
...@@ -2024,7 +2023,7 @@ process_partial_specialization (decl) ...@@ -2024,7 +2023,7 @@ process_partial_specialization (decl)
if (tpd2.parms[j] != 0 if (tpd2.parms[j] != 0
&& tpd.arg_uses_template_parms [j]) && tpd.arg_uses_template_parms [j])
{ {
cp_error ("type `%T' of template argument `%E' depends on template paramter(s)", cp_error ("type `%T' of template argument `%E' depends on template parameter(s)",
type, type,
arg); arg);
break; break;
...@@ -2106,7 +2105,7 @@ check_default_tmpl_args (decl, parms, is_primary, is_partial) ...@@ -2106,7 +2105,7 @@ check_default_tmpl_args (decl, parms, is_primary, is_partial)
if (current_class_type && TYPE_BEING_DEFINED (current_class_type)) if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
/* If we're inside a class definition, there's no need to /* If we're inside a class definition, there's no need to
examine the paramters to the class itself. On the one examine the parameters to the class itself. On the one
hand, they will be checked when the class is defined, and, hand, they will be checked when the class is defined, and,
on the other, default arguments are legal in things like: on the other, default arguments are legal in things like:
template <class T = double> template <class T = double>
...@@ -8024,35 +8023,30 @@ get_class_bindings (tparms, parms, args) ...@@ -8024,35 +8023,30 @@ get_class_bindings (tparms, parms, args)
return vec; return vec;
} }
/* Return the most specialized of the list of templates in FNS that can /* In INSTANTIATIONS is a list of <INSTANTIATION, TEMPLATE> pairs.
produce an instantiation matching DECL, given the explicit template Pick the most specialized template, and return the corresponding
arguments EXPLICIT_ARGS. */ instantiation, or if there is no corresponding instantiation, the
template itself. EXPLICIT_ARGS is any template arguments explicity
mentioned in a template-id. If there is no most specialized
tempalte, error_mark_node is returned. If there are no templates
at all, NULL_TREE is returned. */
tree tree
most_specialized (fns, decl, explicit_args) most_specialized_instantiation (instantiations, explicit_args)
tree fns, decl, explicit_args; tree instantiations;
tree explicit_args;
{ {
tree candidates = NULL_TREE; tree fn, champ;
tree fn, champ, args;
int fate; int fate;
for (fn = fns; fn; fn = TREE_CHAIN (fn)) if (!instantiations)
{
tree candidate = TREE_VALUE (fn);
args = get_bindings (candidate, decl, explicit_args);
if (args)
candidates = scratch_tree_cons (NULL_TREE, candidate,
candidates);
}
if (!candidates)
return NULL_TREE; return NULL_TREE;
champ = TREE_VALUE (candidates); champ = instantiations;
for (fn = TREE_CHAIN (candidates); fn; fn = TREE_CHAIN (fn)) for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
{ {
fate = more_specialized (champ, TREE_VALUE (fn), explicit_args); fate = more_specialized (TREE_VALUE (champ),
TREE_VALUE (fn), explicit_args);
if (fate == 1) if (fate == 1)
; ;
else else
...@@ -8063,18 +8057,43 @@ most_specialized (fns, decl, explicit_args) ...@@ -8063,18 +8057,43 @@ most_specialized (fns, decl, explicit_args)
if (! fn) if (! fn)
return error_mark_node; return error_mark_node;
} }
champ = TREE_VALUE (fn); champ = fn;
} }
} }
for (fn = candidates; fn && TREE_VALUE (fn) != champ; fn = TREE_CHAIN (fn)) for (fn = instantiations; fn && fn != champ; fn = TREE_CHAIN (fn))
{ {
fate = more_specialized (champ, TREE_VALUE (fn), explicit_args); fate = more_specialized (TREE_VALUE (champ),
TREE_VALUE (fn), explicit_args);
if (fate != 1) if (fate != 1)
return error_mark_node; return error_mark_node;
} }
return champ; return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
}
/* Return the most specialized of the list of templates in FNS that can
produce an instantiation matching DECL, given the explicit template
arguments EXPLICIT_ARGS. */
tree
most_specialized (fns, decl, explicit_args)
tree fns, decl, explicit_args;
{
tree candidates = NULL_TREE;
tree fn, args;
for (fn = fns; fn; fn = TREE_CHAIN (fn))
{
tree candidate = TREE_VALUE (fn);
args = get_bindings (candidate, decl, explicit_args);
if (args)
candidates = scratch_tree_cons (NULL_TREE, candidate,
candidates);
}
return most_specialized_instantiation (candidates, explicit_args);
} }
/* If DECL is a specialization of some template, return the most /* If DECL is a specialization of some template, return the most
......
class a {
public:
int f() { return 0; }
int f() const { return 1; }
};
class b : public a {
};
int main()
{
int (b::* ptr1)() = &b::f;
int (b::* ptr2)() const = &b::f;
b ao;
if ((ao.*ptr1)() != 0)
return 1;
if ((ao.*ptr2)() != 1)
return 1;
}
struct B {
int f(int) { return 1; }
};
struct D {
template <class T>
int f(T) { return 0; }
};
int main()
{
int (D::*g)(int) = &D::f;
D d;
return (d.*g)(0);
}
template <class T>
int f(T)
{
return 1;
}
template <class T>
int f(T*)
{
return 0;
}
int main()
{
int (*h)(int*) = &f;
int (&k)(int*) = f;
return (*h)(0) || (*k)(0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment