ПРИМЕЧАНИЕ. Первоначальная близкая причина этого вопроса фактически была решена, поскольку примечание, которое я добавил (сразу ниже этого), на самом деле объясняет, чем этот вопрос отличается от того, который он заявлен как дубликат, и ответ на этот вопрос, который был предоставлен до закрытия вопроса, отвечает на этот конкретный вопрос, а не на другой.
ПРИМЕЧАНИЕ. Я не верю, что это дубликат (как отмечено) шаблона класса с шаблоном друга класса, что здесь на самом деле происходит? потому что эта проблема возникла из-за использования того же имени параметра шаблона во Вложенном шаблоне, где внутреннее использование имени скрывало внешнее использование. В этом вопросе шаблоны не вложены, и нет проблем с использованием одного и того же имени параметра шаблона.
Возможно ли, чтобы класс шаблона, который принимает параметр шаблона нетипа, «подружился» с другим классом шаблона, принимающим параметр шаблона нетипа? Каков синтаксис для этого?
Я попробовал это:
#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 с использованием отчетов --std=c++20:
friend-template-class.cc:31:11: error: 'config' is not a type
31 | template <config> friend class Class1;
| ^~~~~~
и конечно
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;
| ^~~~~~
Чтобы двигаться вперед, я закомментировал объявление друга и «защищенный:», и тогда все работает так, как ожидалось, но я бы предпочел сохранить спецификатор доступа.





Вы можете подружиться с определенной специализацией шаблона класса или с каждой специализацией шаблона класса:
// befriend all specializations
template <Configuration> friend class Small;
// befriend specific specialization
friend class Small<config>;
Спасибо! Ваши примеры показывают, что я делал несколько вещей неправильно: пытался использовать синтаксис «все специализации» для конкретной специализации и что я использовал недопустимое имя класса, введенное как ошибка редактирования при сокращении моей программы до относительно минимального примера.