With reference to the following code
#include <iostream>
#include <tuple>
#include <string>
#include <type_traits>
using std::cout;
using std::endl;
using std::string;
template <typename... Args>
void bar(Args&&...) {}
int change(const string&) { return 1; }
double change(int) { return 1.0; }
int main() {
// bar(1, 2.0, static_cast<int(*)(const string&)>(&change));
bar(1, 2.0, &change);
return 0;
}
I understand that the error in the above code is that the reference to the change
function is ambiguous (which is why the commented line works), but then why does the compiler give this error message?
test.cpp:17:5: error: no matching function for call to 'bar'
bar(1, 2.0, &change);
^~~
test.cpp:11:6: note: candidate function not viable: requires 2 arguments, but 3 were
provided
void bar(Args&&...) {}
^
1 error generated.
This happens both on gcc (>5) as well as clang ( Apple LLVM version 8.0.0 (clang-800.0.42.1)
)
I am just curious as to why both the compilers do not just say that the reference is ambiguous. I feel like it has something to do with how template instantiations work in C++ but I am not sure of the exact reason.
I think the compiler is right, however weird it may be. Template argument deduction rules are different from substitution. The ambiguity in overloaded function resolution in a template parameter pack context does not necessarily mean failure.
See [temp.deduct.call]/p6 :
When P is a function type, function pointer type, or pointer to member function type:
...
-- If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.
So for the last argument of the parameter pack we're in a non-deduced context (not an error).
And [temp.arg.explicit]/p3 :
... A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. ...
So it seems to me (although this last bit doesn't say it explicitly for partially deduced parameter packs) the ambiguous function pointer is simply thrown away at deduction phase, and subsequently the substitution fails because it is trying to substitute 3 arguments into a deduced 2-argument function. It never gets to a point when it needs to resolve ambiguity.
Justin is correct. Running GCC through a debugger leads to these lines of code:
cp_parser_lookup_name(cp_parser*, tree_node*, tag_types, bool, bool, bool, tree_node**, unsigned int) () at ../../gcc/cp/parser.c:24665
24665 {
(gdb)
24667 tree object_type = parser->context->object_type;
(gdb)
24670 if (ambiguous_decls)
(gdb)
24665 {
(gdb)
24667 tree object_type = parser->context->object_type;
(gdb)
24670 if (ambiguous_decls)
(gdb)
24676 parser->context->object_type = NULL_TREE;
...
(gdb) list 24670
24665 {
24666 tree decl;
24667 tree object_type = parser->context->object_type;
24668
24669 /* Assume that the lookup will be unambiguous. */
24670 if (ambiguous_decls)
24671 *ambiguous_decls = NULL_TREE;
24672
24673 /* Now that we have looked up the name, the OBJECT_TYPE (if any) is
24674 no longer valid. Note that if we are parsing tentatively, and
And this is the actual code that emits the diagnostic:
6914 complain);
(gdb)
test.cpp:9:24: error: too many arguments to function ‘void bar(Args&& ...) [with Args = {}]’
bar(1, 2.0, &change);
^
test.cpp:2:6: note: declared here
void bar(Args&&...) {}
...
(gdb) list 6914
6909 /* All other function calls. */
6910 postfix_expression
6911 = finish_call_expr (postfix_expression, &args,
6912 /*disallow_virtual=*/false,
6913 koenig_p,
6914 complain);
6915
6916 if (close_paren_loc != UNKNOWN_LOCATION)
6917 {
6918 location_t combined_loc = make_location (token->location,
Skipping through a bunch of stuff (as it would make this answer unnecessarily long), the actual error occurs during overload resolution:
(gdb)
add_candidates (fns=0x7fffeffb0940, first_arg=first_arg@entry=0x0, args=args@entry=0x7fffeff9baf0, return_type=return_type@entry=0x0, explicit_targs=0x0,
template_only=false, conversion_path=0x0, access_path=0x0, flags=1, candidates=0x7fffffffd320, complain=3) at ../../gcc/cp/call.c:5302
5302 for (; fns; fns = OVL_NEXT (fns))
(gdb)
5365 }
(gdb)
perform_overload_resolution (complain=3, any_viable_p=<synthetic pointer>, candidates=0x7fffffffd320, args=0x7fffeff9baf0, fn=<optimized out>)
at ../../gcc/cp/call.c:4036
4036 *candidates = splice_viable (*candidates, false, any_viable_p);
(gdb)
build_new_function_call(tree_node*, vec<tree_node*, va_gc, vl_embed>**, bool, int) () at ../../gcc/cp/call.c:4111
4111 complain);
(gdb)
4115 if (complain & tf_error)
(gdb)
4119 if (!any_viable_p && candidates && ! candidates->next
(gdb)
4120 && (TREE_CODE (candidates->fn) == FUNCTION_DECL))
(gdb)
4121 return cp_build_function_call_vec (candidates->fn, args, complain);
The error occurs in convert_arguments
:
(gdb) list 3611
3606 allocated = make_tree_vector ();
3607 params = &allocated;
3608 }
3609
3610 nargs = convert_arguments (parm_types, params, fndecl, LOOKUP_NORMAL,
3611 complain);
3612 if (nargs < 0)
3613 return error_mark_node;
3614
3615 argarray = (*params)->address ();
Finally, the diagnostic is emitted in error_num_args
because if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
is false.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.