In the following example I try to access the private member function subscribe() from a templated class type from within its friend function. However it appears that the friend function is only befriended in one instantiation of the class and not the other, hence yielding a "private within this context"-error. Check out the following:
#include <cstdio>
template <typename T>
class my_class
{
template <typename... Ts>
friend auto observe(my_class<Ts>... args) {
([&]{ args.subscribe(); }(), ...);
}
void subscribe() {
printf("subscribed!\n");
}
};
int main()
{
my_class<int> a{};
my_class<bool> b{};
observe(a,b);
}
Error:
<source>:19:20: required from here
<source>:7:17: error: redefinition of 'template<class ... Ts> auto observe(my_class<Ts>...)'
7 | friend auto observe(my_class<Ts>... args) {
| ^~~~~~~
<source>:7:17: note: 'template<class ... Ts> auto observe(my_class<Ts>...)' previously declared here
<source>: In instantiation of 'auto observe(my_class<Ts>...) [with Ts = {int, bool}; T = int]':
<source>:20:12: required from here
<source>:8:29: error: 'void my_class<T>::subscribe() [with T = bool]' is private within this context
8 | ([&]{ args.subscribe(); }(), ...);
| ~~~~~~~~~~~~~~^~
<source>:11:10: note: declared private here
11 | void subscribe() {
| ^~~~~~~~~
Is this actually correct by the compiler?
Yes, this is correct.
my_class<int>andmy_class<bool>are separate classes, and everything inside them will get defined separately for each instantiation of the template. Normally this is fine, because the stuff inside the classes is class members, so i.e.my_class<int>::subscribeandmy_class<bool>::subscribeare different functions.But
observeis not a class member, so the fact that it gets defined by bothmy_class<int>andmy_class<bool>is a violation of the One Definition Rule.What you need to do is move the definition of
observeoutside ofmy_classso that it only gets defined once:Demo