Ambigüedad que implica operador de conversión con plantilla y constructor de copia implícito


Clang y gcc difieren en el comportamiento para el siguiente código:

struct foo
{
    foo(int);
};

struct waldo
{
    template <typename T>
    operator T();
};

int main()
{
    waldo w;
    foo f{w};
}

Este código es aceptado por clang, con el constructor foo(int) siendo llamado. Sin embargo, gcc se queja de una ambigüedad entre el constructor foo(int) y los constructores de copia y movimiento generados implícitamente:

test.cpp: In function 'int main()':
test.cpp:15:12: error: call of overloaded 'foo(<brace-enclosed initializer list>)' is ambiguous
     foo f{w};
            ^
test.cpp:15:12: note: candidates are:
test.cpp:3:5: note: foo::foo(int)
     foo(int);
     ^
test.cpp:1:8: note: constexpr foo::foo(const foo&)
 struct foo
        ^
test.cpp:1:8: note: constexpr foo::foo(foo&&)

¿Quién tiene razón?

También es interesante notar que si foo f{w} se cambia a foo f(w) (note el cambio de llaves a paréntesis), tanto gcc como clang dan un error. Esto me hace espero que el comportamiento de gcc para el ejemplo anterior (es decir, dar un error) sea correcto, de lo contrario habría una extraña inconsistencia entre las formas () y {} de inicialización.

EDIT : Siguiendo la sugerencia de Kerrek SB , probé delete con el constructor de copia de foo:

struct foo
{
    foo(int);
    foo(const foo&) = delete;
};

El comportamiento sigue siendo el mismo.

Author: HighCommander4, 2013-04-17

1 answers

Para la inicialización de la lista, si el elemento de la lista tiene un elemento (aquí, w), y se considera un constructor de una clase X con el parámetro "referencia a const/volatile X", no se consideran conversiones definidas por el usuario. Por lo tanto, no se pueden usar el constructor copiar y mover de foo. Así que el constructor foo(int) es elegido inequívocamente.

Así que Clang es correcto aquí.

EDITAR: Para la gente de Estándares aquí, ver 13.3.3.1p4

 11
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-17 09:19:10