The following snippet:
#include <functional>
struct X {
X(std::function<double(double)> fn); // (1)
X(double, double); // (2)
template <class T>
auto operator()(T const& t) const { // (3)
return t.foo();
}
};
int main() {
double a, b;
auto x = X(a, b);
return 0;
}
...fails to compile with both clang
(4.0.1) and g++
(6.3, 7.2) when using -std=c++14
— tested on OSX and godbolt.org.
But it compiles without problem if:
(1)
;double
) in (3)
;-> decltype(t.foo())
) in (3)
;-std=c++1z
(thanks @bolov).Maybe there is something obvious that I am missing here... Is there any issue with this code? Is this a bug?
You are copy initializing x
. And X
is a tricky type for the following reasons:
It can be constructed from any callable object that can be called with a double argument. And whose return type is convertible to a double.
It is itself a callable object that can be called with a double argument. But the return type needs deducing.
There's a compiler generated copy constructor for X
.
The ambiguity is starting to become obvious here, I hope. There is need for overload resolution.
When your remove the first c'tor, it gets rid of the ambiguity in an obvious fashion. The interesting case is the function call operator.
You see, std::function
can only be constructed from the callable it is passed (the templated c'tor will only participate in overload resolution) if the conversions between arguments to parameters, and between return types are possible. This is all done in an unevaluated context, so the templated function call operator isn't odr-used, and therefore not instantiated.
When the return type is a placeholder type, the std::function
c'tor cannot easily resolve if it should be constructed or not. Compilation fails during overload resolution, even though had it succeeded, the copy c'tor of X
would have been selected.
As @VTT suggested in a comment, marking the c'tor that accepts a std::function
as explicit will also resolve the ambiguity. All on account of the compiler not having to rank the implicit conversion sequence at all.
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