I think the problem is your converting constructor template template<typename F2> py_catch(F2&&)
is too greedy. Another way to trigger the error is:
int main() {
auto x( make_py_catch([]{}) );
auto y(x);
}
This copy-construction uses an lvalue of some type py_catch<..>
. The copy-ctor expects a py_catch<..> const&
, whereas your greedy template provides an overload with a parameter of type py_catch<..>&
. A special rule in [over.ics.rank]/3 now says the overload taking the reference-to-less-qualified-type is preferred. Therefore, not the copy-ctor, but the constructor template is called, which tries to initialize the data member (lambda) using the whole py_catch<..>
object (instead of its func
member).
A simple, but possibly not optimal solution is to provide another copy-ctor for non-const lvalues py_catch(py_catch&) = default;
. But then, when you use inheritance or user-defined conversions, the constructor template will still be preferred.
Another solution is to use some SFINAE on the constructor template; for example check for is_same
, is_base_of
or something similar (remember to remove_reference
the possible reference from F2
). is_convertible
might work as well, but I suspect it would be recursively trying to use the constructor template to do its check.