Repository navigation
Friend function template with friend after a dependent return type isn't matched by its later definition ("more than one instance ... matches") #442
Description
Issue Summary
A class template declares a friend function template with the friend
specifier written after the return type:
typename C<U>::size_type friend erase_if(C<U> &c, P p);The front end then treats the namespace-scope definition of the same function
template as a different template, so an unqualified call reports "more than
one instance of erase_if matches the argument list". GCC and Clang accept
the code. Writing friend first (friend typename C<U>::size_type erase_if(...)),
or using a non-dependent return type, works.
Boost.Unordered declares erase_if this way for its open-addressing
containers (unordered_flat_map, unordered_flat_set, unordered_node_map,
unordered_node_set), so any call to erase_if on them fails to compile. This
fails 2 Boost.Unordered tests (foa_erase_if, foa_post_move_tests).
Reproducing Source Code
namespace N {
template <class T> class C {
int x = 0;
template <class U, class P>
typename C<U>::size_type friend erase_if(C<U> &c, P p);
public:
using size_type = unsigned long;
};
template <class T, class P>
typename C<T>::size_type erase_if(C<T> &c, P p) { return c.x; }
}
int main() { N::C<int> c; return (int)erase_if(c, 0); }Command-line Options
cpfe --c++17 friend_erase_if.cpp
Type of Issue
[Front End] This code SHOULD compile with these options.
Additional Details
Expected: compiles (g++ 15.3.1 compiles and runs it, exit status 0).
Actual (linux-gcc-release and linux-gcc-debug; also with --c++20, and in
GNU mode through eccp):
"friend_erase_if.cpp", line 12: error: more than one instance of "erase_if"
matches the argument list:
function template "N::C<U>::size_type N::erase_if(N::C<U> &, P)"
(declared at line 5)
function template "N::C<T>::size_type N::erase_if(N::C<T> &, P)"
(declared at line 10)
argument types are: (N::C<int>, int)
int main() { N::C<int> c; return (int)erase_if(c, 0); }
^
1 error detected in the compilation of "friend_erase_if.cpp".
Variants checked:
| Declaration in the class | Result |
|---|---|
typename C<U>::size_type friend erase_if(C<U> &, P); |
error (above) |
friend typename C<U>::size_type erase_if(C<U> &, P); |
compiles |
int friend erase_if(C<U> &, P); (non-dependent return type) |
compiles |
So the combination of a decl-specifier friend after the type and a
dependent return type that names the enclosing class template seems to give
the friend declaration a different signature than the matching namespace-scope
declaration.
Boost: boost/unordered/unordered_flat_map.hpp:60-62 declares
template <class K, class V, class H, class KE, class A, class Pred>
typename unordered_flat_map<K, V, H, KE, A>::size_type friend erase_if(
unordered_flat_map<K, V, H, KE, A>& set, Pred pred);and lines 776-783 define it at namespace scope. unordered_flat_set.hpp:57-58,
unordered_node_map.hpp:62-63 and unordered_node_set.hpp:61-62 use the same
pattern. libs/unordered/test/unordered/erase_if.cpp:70,99,112 and
post_move_tests.cpp:358 then fail with the error above.
Environment: edgcpp/dev-env Docker image (Fedora 43, GCC 15.3.1) on
x86-64, boost branch at c36e03a67c.
Reproducing (Standard) Configuration(s)
linux-gcc-release
Reproducing (Non-standard) Configuration
No response
I acknowledge that:
- I have checked open issues and existing discussions before filing this report.
- The reproducing source code that I have provided does not depend on headers that I have not included with my submission.
- I have reduced the reproducing source code to the best of my ability.
- I have selected at least one standard configuration or uploaded a non-standard configuration dump.
- I understand code shared via this form is NOT confidential.
- I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests.
- I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under project license unless I included a
LICENSE.txtfile in my.zipor.tar.gzupload. If I included aLICENSE.txtfile, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Activity