When trying to use decltype on a member function which has a late specified return type calling a private member function of a friend class I receive the below error. My understanding is that the "friend struct base<derived>;" in derived should cause this error to not occur which is the case with clang. Adding "foo_argument<derived>" does cause the error to disappear. I apologize for the length of the example, but I've had difficulty reproducing it with fewer lines of code. main.cpp: In instantiation of ‘struct foo_argument<derived>’: main.cpp:43:47: required from here main.cpp:9:50: error: no matching function for call to ‘foo_argument<derived>::test(<unresolved overloaded function type>)’ using type = decltype(test(&T::template foo<>)); ^ main.cpp:9:50: note: candidate is: main.cpp:7:16: note: template<class Ret, class C, class Arg> static Arg foo_argument<T>::test(Ret (C::*)(Arg)) [with Ret = Ret; C = C; Arg = Arg; T = derived] static Arg test(Ret (C::*)(Arg)); ^ main.cpp:7:16: note: template argument deduction/substitution failed: main.cpp:35:9: error: ‘int derived::foo_impl(int)’ is private int foo_impl(int i) ^ main.cpp:9:50: error: within this context using type = decltype(test(&T::template foo<>)); The below example can be seen at: http://coliru.stacked-crooked.com/a/3ffd6557434a3ab9 #include <utility> template<class T> struct foo_argument { template<class Ret, class C, class Arg> static Arg test(Ret (C::*)(Arg)); using type = decltype(test(&T::template foo<>)); }; template<class T, class D> struct dependent { typedef T type; }; template<class T, class D> using Dependent = typename dependent<T, D>::type; template<class T> struct base { friend struct foo_argument<T>; template<class Ignore = void> auto foo(int i) -> decltype(std::declval<Dependent<T&, Ignore>>().foo_impl(i)) { return static_cast<T&>(*this).foo_impl(i); } }; struct derived : base<derived> { friend struct base<derived>; //friend struct foo_argument<derived>; private: int foo_impl(int i) { return 123 + i; } }; int main() { using foo_arg_type = foo_argument<derived>::type; }
This seems to be a regression, the example was accepted in gcc 4.7.3. The following is a first attempt to reduce the complexity of the example, in particular by removing any library dependencies and any possible interaction with alias templates and alias typedefs, furthermore the additional friend declaration in template base is neither needed nor should it be relevant for this issue, therefore has been removed: //--------------- template<class T> T&& declval(); template<class T> struct foo_argument { template<class Ret, class C, class Arg> static Arg test(Ret (C::*)(Arg)); typedef decltype(test(&T::template foo<>)) type; }; template<class T, class> struct dependent { typedef T type; }; template<class T> struct base { template<class Ignore = void> auto foo(int i) -> decltype(declval< typename dependent<T&, Ignore>::type >().foo_impl(i)); }; struct derived : base<derived> { friend struct base<derived>; private: int foo_impl(int i); }; int main() { foo_argument<derived>::type var = 0; return var; } //---------------
Thanks Daniel.
Author: jason Date: Fri Dec 13 03:58:48 2013 New Revision: 205952 URL: http://gcc.gnu.org/viewcvs?rev=205952&root=gcc&view=rev Log: PR c++/58954 * pt.c (resolve_overloaded_unification): Use instantiate_template. Added: trunk/gcc/testsuite/g++.dg/cpp0x/access02.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c
Author: jason Date: Fri Dec 13 03:59:10 2013 New Revision: 205954 URL: http://gcc.gnu.org/viewcvs?rev=205954&root=gcc&view=rev Log: PR c++/58954 * pt.c (resolve_overloaded_unification): Discard access checks. Added: branches/gcc-4_8-branch/gcc/testsuite/g++.dg/cpp0x/access02.C Modified: branches/gcc-4_8-branch/gcc/cp/ChangeLog branches/gcc-4_8-branch/gcc/cp/pt.c
Fixed for 4.8.3/4.9.