varias una saber referencias referencia que problema misma mas las iterativo hoja hay hace esta encontro eliminar elimina donde cómo con como circulares calculo c++ c++11 templates gcc clang

c++ - una - referencia circular c#



¿Por qué el compilador no da un error de referencia ambiguo? (2)

Creo que el compilador tiene razón, por extraño que sea. Las reglas de deducción de argumentos de plantilla son diferentes de la sustitución. La ambigüedad en la resolución de la función sobrecargada en un contexto de paquete de parámetros de plantilla no significa necesariamente un fallo.

Ver [temp.deduct.call]/p6 :

Cuando P es un tipo de función, tipo de puntero de función o puntero al tipo de función miembro:

...

- Si el argumento es un conjunto de sobrecarga (que no contiene plantillas de función), se intenta deducir el argumento de prueba utilizando cada uno de los miembros del conjunto. Si la deducción es exitosa solo para uno de los miembros del conjunto de sobrecarga, ese miembro se usa como el valor de argumento para la deducción. Si la deducción es exitosa para más de un miembro del conjunto de sobrecarga, el parámetro se trata como un contexto no deducido.

Entonces, para el último argumento del paquete de parámetros, estamos en un contexto no deducido (no un error).

Y [temp.arg.explicit]/p3 :

... Un paquete de parámetros de la plantilla final que no se deduce de otra manera se deducirá a una secuencia vacía de argumentos de la plantilla. ...

Así que me parece (aunque este último bit no lo dice explícitamente para los paquetes de parámetros parcialmente deducidos) el puntero de la función ambigua simplemente se desecha en la fase de deducción, y posteriormente la sustitución falla porque intenta sustituir 3 argumentos en una deducida Función de 2 argumentos. Nunca llega a un punto en el que necesita resolver la ambigüedad.

Con referencia al siguiente código

#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; }

Entiendo que el error en el código anterior es que la referencia a la función de change es ambigua (razón por la cual funciona la línea comentada), pero entonces ¿por qué el compilador da este mensaje de error?

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.

Esto sucede tanto en gcc (> 5) como en clang ( Apple LLVM version 8.0.0 (clang-800.0.42.1) )

Solo tengo curiosidad por saber por qué los compiladores no solo dicen que la referencia es ambigua. Siento que tiene algo que ver con cómo funcionan las instancias de las plantillas en C ++, pero no estoy seguro de la razón exacta.


Justin es correcto Ejecutar GCC a través de un depurador conduce a estas líneas de código:

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

Y este es el código real que emite el diagnóstico:

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,

Al saltear un montón de cosas (ya que haría que esta respuesta fuera innecesariamente larga), el error real ocurre durante la resolución de sobrecarga:

(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);

El error se produce en 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 ();

Finalmente, el diagnóstico se emite en error_num_args porque if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE) es falso.