Sto giocando con un trucco per sovraccaricare lambda in C++. In particolare:lambda sovraccaricato in C++ e differenze tra clang e gcc
// 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;
}
Ora, il programma di cui sopra compila e funziona bene in clang:
$ clang++ -g -std=c++14 test01.cpp -o test01
$ ./test01
3
4
boblarry
Esso non può essere compilato in 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
Perché c'è una differenza? Per la cronaca, sto usando gcc 4.9.2 e clang 3.5.0.
Modifica 1
Evidentemente, questo frammento di codice non è riuscito a compilare su VC così ed era già stata reported. Detto questo, Sean Middleditch ha registrato una versione funzionante del codice sovraccarico:
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...);
}
Sono ancora interessato a capire il motivo per cui questa versione del codice Lambda sovraccarico funziona, ma l'originale non lo fa.
Questo potrebbe essere dovuto alla semplificazione del codice per questa domanda, ma dal momento che stai usando C++ 14, '[] (auto x, auto y) {return x + y;}' produrrebbe un lambda con le stesse capacità sovraccariche. –
@DrewDormann Di sicuro. Davvero, stavo solo cercando di trovare un singolo esempio per mostrare cosa stava succedendo. Più tardi, mi piacerebbe usarlo per casi più complicati. – wyer33
È sorprendente che il codice originale sia stato compilato in clang. La regola generale è che gli stessi nomi in diverse classi base non sovraccaricano. –