There used to be a paragraph in the standard which stated that
the names of a namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope. Such names may be found under for associated classes.
template <typename T> struct number {
number(int);
friend number gcd(number x, number y) { return 0; }
};
void g() {
number<double> a(3), b(4);
a = gcd(a, b); // finds gcd becuase numer<double> is an associated class,
// making gcd visible in its namespace (global scope)
b = gcd(3, 4); // error: gcd is not visible
}
This feature has been used to capture and retrieve a metaprogramming state at compile time.
template <int X>
struct flag {
friend consteval int f(flag<X>);
};
template <int X, int N>
struct injecter {
friend consteval int f(flag<X>) { return N; }
};
template <int N = 0, auto = []{}>
consteval auto inject() {
if constexpr (requires { f(flag<X>{}); }) {
return inject<N 1>();
} else {
void(injecter<X>{});
return f(flag<X>{});
}
}
static_assert(inject() == 0);
static_assert(inject() == 1);
static_assert(inject() == 2);
static_assert(inject() == 3);
// ...
As far as I know, there is an issue from CWG which aimed to make such behaviour ill-formed although the mechanism for prohibiting them is as yet undetermined. However, as the paragraph seems to be absent from the latest draft, I'm wrondering if friend injections will be ill-formed in C 23.
CodePudding user response:
From P1787R6:
Merged [temp.inject] into [temp.friend]
(Adopted in N4885 in March 2021)
The current draft (N4901) reads ([temp.friend]p2):
Friend classes, class templates, functions, or function templates can be declared within a class template. When a template is instantiated, its friend declarations are found by name lookup as if the specialization had been explicitly declared at its point of instantiation
Which seems to cover the old [temp.inject]p2