The following lambda overloads are not ambiguous but they are reported as such. template <class... Fs> struct overload_set : Fs... { overload_set(Fs... f) : Fs(f)... {} }; template <class... Fs> overload_set<Fs...> overload(Fs... x) { return overload_set<Fs...>(x...); } int main(void) { double d = 10; overload( [](int i) { }, [](double d) { }, [](char c) { } )(d); }
This looks like a more fundamental name lookup problem of gcc to me. It can be reproduced with function object types that are no lambda closures: template <class... Fs> struct overload_set : Fs... { overload_set(Fs... f) : Fs(f)... {} }; template <class... Fs> overload_set<Fs...> overload(Fs... x) { return overload_set<Fs...>(x...); } template<class T> struct Closure { void operator()(T) const {} using FPtr = void(*)(T); operator FPtr() const; }; int main() { double d = 10; overload( Closure<int>(), Closure<double>(), Closure<char>() )(d); }
Thanks Daniel. Could even be a duplicate then.
This should be closed as invalid. The lookup for `operator()` is indeed ambiguous, (see [class.member.lookup]/6 - the merge produces an invalid set), and GCC correctly reports it as such. In the absence of using-declarations, names from different base classes don't overload.
Daniel, is there agreement now about this bug?
Barring further comments, I'm going to add a testcase and close this. (Note, current clang still accepts it)
Unrelated to lambdas really. Here is a C++98 code which shows the same issue with clang: template<class t> struct i { t operator()(t i); }; struct overload_set1 : i<int>, i<double> { overload_set1() {} }; int main(void) { double d1 = 10; overload_set1 tt; tt(d1); } To make the original code work (you need C++17 really): Adding using Fs::operator()...; allows GCC (and ICC) to work. So this is a bug in clang. I don't think we need a testcase as we must likely already have a C++98 one even.