Consider the task of implementing an overload_two class so that the following code compiles:
int main()
{
overload_two o{
[](int) { return 1; },
[](char){ return 2; }
};
static_assert(o(0) + o('a') == 3);
}
A first attempt would look something like this:
template <typename F, typename G>
struct overload_two : F, G
{
overload_two(F f, G g) : F{f}, G{g} { }
};
Of course, this fails with the following error (gcc 11.0.1):
<source>:15:22: error: request for member 'operator()' is ambiguous 15 | static_assert(o(0) + o('a') == 3); | ^ <source>:12:9: note: candidates are: 'main()::<lambda(char)>' 12 | [](char){ return 2; } | ^ <source>:11:9: note: 'main()::<lambda(int)>' 11 | [](int) { return 1; }, | ^
The intended solution is to bring both F::operator() and G::operator() into scope with using declarations. However -- very surprisingly -- introducing a seemingly unrelated operator() also works:
template <typename F, typename G>
struct overload_two : F, G
{
overload_two(F f, G g) : F{f}, G{g} { }
auto operator()(F&) { } // wtf?
};
What's more, clang 13.0.0 seems to work without neither the using declaration or the random operator(): live example on godbolt.org.
My questions are:
Is gcc correct in rejecting the implementation of
overload_twowithout anyoperator()orusingdeclaration?Is gcc correct in accepting the implementation of
overload_twowithoperator()(F&)and nousingdeclaration?Is clang correct in accepting the implementation of
overload_twowithout anyoperator()orusingdeclaration?