meaning installed for descargar c++ c++11 gcc clang overload-resolution

installed - Lambdas sobrecargadas en C++ y diferencias entre clang y gcc



clang windows (2)

A mí me parece un error de Clang.

La regla general es que las funciones miembro del mismo nombre en diferentes clases base no se sobrecargan. Por ejemplo:

struct Foo { void bar(); }; struct Baz { void bar(int); }; struct Quux : Foo, Baz { }; int main() { Quux().bar(); } // error on both GCC and Clang

Por alguna razón, Clang no puede diagnosticar esta ambigüedad para el operator() .

Una using-declaration eleva a los miembros de la clase base nombrada al alcance de la clase derivada, lo que les permite sobrecargarse. Por lo tanto:

struct Quux_2 : Foo, Baz { using Foo::bar; using Baz::bar; }; Quux_2().bar(); // OK.

En la versión funcional del código, las declaraciones de using recursivamente llevan cada declaración de operator() en los argumentos de la plantilla al alcance de la clase más derivada, lo que les permite sobrecargarse.

Estoy jugando con un truco para sobrecargar lambdas en C ++. Específicamente:

// For std::function #include <functional> // For std::string #include <string> // For std::cout #include <iostream> template <class... F> struct overload : F... { overload(F... f) : F(f)... {} }; template <class... F> auto make_overload(F... f) { return overload<F...>(f...); } int main() { std::function <int(int,int)> f = [](int x,int y) { return x+y; }; std::function <double(double,double)> g = [](double x,double y) { return x+y; }; std::function <std::string(std::string,std::string)> h = [](std::string x,std::string y) { return x+y; }; auto fgh = make_overload(f,g,h); std::cout << fgh(1,2) << std::endl; std::cout << fgh(1.5,2.5) << std::endl; std::cout << fgh("bob","larry") << std::endl; }

Ahora, el programa anterior compila y funciona bien en clang:

$ clang++ -g -std=c++14 test01.cpp -o test01 $ ./test01 3 4 boblarry

No se compila en gcc:

$ g++ -g -std=c++14 test01.cpp -o test01 test01.cpp: In function ''int main()'': test01.cpp:36:25: error: request for member ''operator()'' is ambiguous std::cout << fgh(1,2) << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] test01.cpp:37:29: error: request for member ''operator()'' is ambiguous std::cout << fgh(1.5,2.5) << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] test01.cpp:38:35: error: request for member ''operator()'' is ambiguous std::cout << fgh("bob","larry") << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] Makefile:2: recipe for target ''all'' failed make: *** [all] Error 1

¿Por qué hay una diferencia? Para el registro, estoy usando gcc 4.9.2 y clang 3.5.0.

Editar 1

Evidentemente, este fragmento de código no pudo compilarse también en VC y ya se había reported . Dicho esto, Sean Middleditch publicó una versión funcional del código sobrecargado:

template<class F1, class... Fs> struct overload : F1, overload<Fs...> { using F1::operator(); using overload<Fs...>::operator(); overload(F1 f1, Fs... fs) : F1(f1), overload<Fs...>(fs...) {} }; template<class F1> struct overload<F1> : F1 { using F1::operator(); overload(F1 f1) : F1(f1) {} }; template <class... F> auto make_overload(F... f) { return overload<F...>(f...); }

Todavía estoy interesado en entender por qué funciona esta versión del código lambda sobrecargado, pero el original no.


El código original no debe compilarse, gcc es correcto aquí. Ver [class.member.lookup]:

De lo contrario (es decir, C no contiene una declaración de f o el conjunto de declaraciones resultante está vacío), S (f, C) está inicialmente vacío. Si C tiene clases base, calcule el conjunto de búsqueda para f en cada subobjeto de clase base directa Bi, y combine cada conjunto de búsqueda S (f, Bi) a su vez en S (f, C).
- [..]
- De lo contrario, si los conjuntos de declaración de S (f, Bi) y S (f, C) difieren, la fusión es ambigua ...

El conjunto de declaración inicial está vacío (la overload no tiene métodos), por lo tanto, combine todas las bases, todas las cuales tienen conjuntos diferentes. Entonces la fusión debería fallar. Sin embargo, esa regla solo se aplica si el conjunto de declaración de overload está vacío, por lo que funciona la adición explícita del using F1::operator() .