NOTE: The original close reason for this question WAS in fact resolved, as the note I added (immediately below this) does in fact explain how this question is different from the one it's claimed as a duplicate of, and the answer to this question, which was provided before the question was closed, answers this specific question and not the other one.
NOTE: I do not believe this is a duplicate (as marked) of Class template with template class friend, what's really going on here? because that problem was due to the use of the same template parameter name in a NESTED template, where the inner use of the name hid the outer use. In this question the templates are not nested, and the there is not a problem with the use of the same template parameter name.
Is it possible for a template class that takes a non-type template parameter to 'friend' another template class taking an non-type template parameter? What's the syntax for doing that?
I tried this:
#include <iostream>
struct Configuration
{
static constexpr int foo = 12;
};
// forward declaration of template class Big
template <Configuration config>
class Big;
template <Configuration config>
class Small
{
public:
Small(Big<config>& big):
big(big)
{
}
void doit()
{
std::cout << big.burger + config.foo << "\n";
}
protected:
Big<config>& big;
};
template <Configuration config>
class Big
{
template <config> friend class Small;
public:
Big():
small(*this)
{
}
void doit()
{
small.doit();
}
protected:
Small<config> small;
double burger = 42.3;
};
int main([[maybe_unused]] int argc,
[[maybe_unused]] char *argv[])
{
Configuration conf;
Big<conf> big;
big.doit();
}
GCC 14.0.1 using --std=c++20 reports:
friend-template-class.cc:31:11: error: 'config' is not a type
31 | template <config> friend class Class1;
| ^~~~~~
and of course
friend-template-class.cc:23:22: error: 'double Big<Configuration()>::burger' is protected within this context
23 | std::cout << big.burger + config.foo << "\n";
| ~~~~^~~~~~
friend-template-class.cc:48:10: note: declared protected here
48 | double burger = 42.3;
| ^~~~~~
To move forward, I commented out the friend declaration and the "protected:", and then it performs as expected, but I really would prefer to keep the access specifier.
You can either befriend a specific specialization of a class template, or every specialization of the class template:
// befriend all specializations
template <Configuration> friend class Small;
// befriend specific specialization
friend class Small<config>;