https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65942
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |ASSIGNED Component|c++ |libstdc++ --- Comment #9 from Jonathan Wakely <redi at gcc dot gnu.org> --- Further reduced: template<typename _Tp> _Tp&& declval() noexcept; template<typename Arg> struct function { template<typename Functor, typename = decltype( declval<Functor&>()(declval<Arg>()) )> function(Functor) { } function() { } bool operator()(Arg) const; }; template<typename Compare> struct Iter_comp { Compare m_comp; Iter_comp(Compare comp) : m_comp(comp) { } template<typename Iterator> #ifndef OK constexpr #endif bool operator()(Iterator it) const { return m_comp(*it); } }; using F = function<int>; F f; Iter_comp<F> c{ f }; auto c2 = c; GCC says: f.cc: In instantiation of ‘constexpr bool Iter_comp<Compare>::operator()(Iterator) const [with Iterator = int; Compare = function<int>]’: f.cc:8:52: required by substitution of ‘template<class Functor, class> function<Arg>::function(Functor) [with Functor = Iter_comp<function<int> >; <template-parameter-1-2> = <missing>]’ f.cc:38:11: required from here f.cc:32:23: error: invalid type argument of unary ‘*’ (have ‘int’) { return m_comp(*it); } ^ and Clang says: f.cc:32:23: error: indirection requires pointer operand ('int' invalid) { return m_comp(*it); } ^~~ f.cc:8:35: note: in instantiation of function template specialization 'Iter_comp<function<int> >::operator()<int>' requested here typename = decltype( declval<Functor&>()(declval<Arg>()) )> ^ f.cc:9:7: note: in instantiation of default argument for 'function<Iter_comp<function<int> > >' required here function(Functor) { } ^~~~~~~~ f.cc:38:11: note: while substituting deduced template arguments into function template 'function' [with Functor = Iter_comp<function<int> >, $1 = (no value)] auto c2 = c; ^ 1 error generated. What I don't understand is why function<int>::function<Comp_iter<function<int>> ever gets considered for overload resolution. Where does that come from and why? Anyway, it seems we can fix the library by constraining _Iter_comp_iter::operator() template<typename Iterator, typename = decltype(declval<Compare&>()(*declval<Iterator>()))> #ifndef OK constexpr #endif bool operator()(Iterator it) const { return m_comp(*it); } That prevents it being instantiated as a possible argument to std::function. Changing component back to libstdc++