Consider the following code:
// Preamble
#include <iostream>
#include <type_traits>
// A base class
template <class T>
struct base {void operator()(T){};};
// Two derived classes inheriting from the same base classes
template <class... T>
struct derived1: base<T>... {using base<T>::operator()...;};
template <class... T>
struct derived2: base<T>... {using base<T>::operator()...;};
// A class inheriting from both derived1 and derived2
template <class T0, class... T>
struct functor: derived1<T0>, derived2<T0, T...> {
using derived1<T0>::operator();
using derived2<T0, T...>::operator();
};
// Main function
int main() {
std::cout << std::is_invocable_v<functor<int, float, char>, int> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, float> << "\n";
std::cout << std::is_invocable_v<functor<int, float, char>, char> << "\n";
return 0;
}
The call to functor<int, float, char>::operator()(int)
is ambiguous because this operator is inherited twice, from both derived1
and derived2
(and let's say that for convoluted SFINAE purpose I want it to be ambiguous).
On clang++-5.0
, the output of the code is 0
, 1
, 1
, while on g++-7.2
the output is 1
, 1
, 1
. Which one is right? And would there be a workaround, creating a new struct is_unambiguously_invocable
while waiting for the bugfix?
Your reasoning is correct. Note that gcc correctly disallows the call itself:
functor<int, float, char>()(42); // error: base<int> is an ambiguous base
It just incorrectly detects that this invocation is ill-formed. Reported this as gcc bug 84869. T.C. added a further reduced reproduction in the bug report that does not have library dependencies:
struct base { void operator()(int ) { } }; struct a : base { }; struct b : base { }; struct f: a, b { using a::operator(); using b::operator(); }; template<class T> auto g(int) -> decltype(T()(0), 0); template<class T> auto g(...) -> long; template<class, class> struct Same; template<class T> struct Same<T, T> {}; Same<decltype(g<f>(0)), long> s; // should be okay, but gcc errors because it // thinks decltype(g<f>(0)) is int
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With