Bug 58820 - lambda multiple inheritance operator() not ambiguous
Summary: lambda multiple inheritance operator() not ambiguous
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-10-21 07:36 UTC by Sumant Tambe
Modified: 2021-08-27 20:47 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-10-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sumant Tambe 2013-10-21 07:36:17 UTC
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);
}
Comment 1 Daniel Krügler 2013-10-21 12:18:43 UTC
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);
}
Comment 2 Paolo Carlini 2013-10-21 12:22:46 UTC
Thanks Daniel. Could even be a duplicate then.
Comment 3 TC 2017-06-11 01:36:24 UTC
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.
Comment 4 Paolo Carlini 2017-10-04 08:57:20 UTC
Daniel, is there agreement now about this bug?
Comment 5 Paolo Carlini 2018-03-03 00:44:37 UTC
Barring further comments, I'm going to add a testcase and close this.
(Note, current clang still accepts it)
Comment 6 Andrew Pinski 2021-08-27 20:47:34 UTC
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.