Consider a simplified form of std::bind that just wraps a functor and calls it, preserving the cv-qualifiers on the wrapper:
#include <utility> using std::declval; template<typename Sig> struct result_of; template<typename Fn, typename... ArgTypes> struct result_of<Fn(ArgTypes...)> { typedef decltype( declval<Fn>()( declval<ArgTypes>()... ) ) type; }; template<typename Fn> struct Binder { Fn functor; typename result_of<Fn()>::type call() { return functor(); } typename result_of<const Fn()>::type call() const { return functor(); } typename result_of<volatile Fn()>::type call() volatile { return functor(); } typename result_of<const volatile Fn()>::type call() const volatile { return functor(); } }; struct F { int operator()() { return 0; } }; int main() { Binder<F> b = { }; b.call(); } This gives: bind.cc: In instantiation of 'result_of<const F()>': bind.cc:26:3: instantiated from 'Binder<F>' bind.cc:52:13: instantiated from here bind.cc:11:65: error: passing 'const F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc:11:65: error: passing 'const F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc: In instantiation of 'result_of<volatile F()>': bind.cc:32:3: instantiated from 'Binder<F>' bind.cc:52:13: instantiated from here bind.cc:11:65: error: passing 'volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc:11:65: error: passing 'volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc: In instantiation of 'result_of<const volatile F()>': bind.cc:38:3: instantiated from 'Binder<F>' bind.cc:52:13: instantiated from here bind.cc:11:65: error: passing 'const volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc:11:65: error: passing 'const volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers using: Using built-in specs. COLLECT_GCC=/home/jwakely/gcc/4.x/bin/g++ COLLECT_LTO_WRAPPER=/home/jwakely/gcc/4.x/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../src/gcc/configure --prefix=/n/14/jwakely/gcc/4.x --with-mpfr=/opt/cfarm/mpfr-2.4.1 --with-gmp=/opt/cfarm/gmp-4.2.4 --enable-libstdcxx-time=rt --enable-languages=c,c++ --disable-bootstrap : (reconfigured) ../src/gcc/configure --prefix=/n/14/jwakely/gcc/4.x --with-mpfr=/opt/cfarm/mpfr-2.4.1 --with-gmp=/opt/cfarm/gmp-4.2.4 --enable-libstdcxx-time=rt --enable-languages=c,c++ --disable-bootstrap Thread model: posix gcc version 4.5.0 20091121 (experimental) (GCC) The problem is that overload resolution for b.call() causes result_of<cv-qual Fn>::type to be instantiated, which gives an error when "cv-qual" does not match the cv-quals of Fn::operator() Shouldn't SFINAE cause those invalid instantiations to be ignored, silently removing the invalid overloads from the overload set, leaving just the one I'm trying to call? This is blocking my attempts to make std::bind conform to the C++0x WP, particularly forwarding cv-quals. If g++ is right, what extra hoops do I need to jump through to make the code above work? I get the same result if I use decltype directly, rather than via result_of, which is why I think this is a sfinae bug, not a problem with using result_of here: #include <utility> using std::declval; template<typename Fn> struct Binder { Fn functor; decltype( declval<Fn&>()() ) call() { return functor(); } decltype( declval<const Fn&>()() ) call() const { return functor(); } decltype( declval<volatile Fn&>()() ) call() volatile { return functor(); } decltype( declval<const volatile Fn&>()() ) call() const volatile { return functor(); } }; struct F { int operator()() { return 0; } }; int main() { Binder<F> b = { }; b.call(); } bind.cc: In instantiation of 'Binder<F>': bind.cc:43:13: instantiated from here bind.cc:17:3: error: passing 'const F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc: In instantiation of 'Binder<F>': bind.cc:43:13: instantiated from here bind.cc:23:3: error: passing 'volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers bind.cc: In instantiation of 'Binder<F>': bind.cc:43:13: instantiated from here bind.cc:29:3: error: passing 'const volatile F' as 'this' argument of 'int F::operator()()' discards qualifiers N.B. tr1::bind can handle this because tr1::result_of doesn't preserve cv-quals, which means it gives the wrong result when operator() is overloaded for different cv qualifiers. -- Summary: [C++0x] SFINAE failure with cv-qualifiers Product: gcc Version: 4.5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: redi at gcc dot gnu dot org OtherBugsDependingO 35569 nThis: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42132