Я бы хотел скомпилировать приведенный ниже пример. У меня есть шаблон класса, который определяет шаблон функции друга, но по умолчанию он не отображается в окружающем пространстве имен.
namespace ns {
template<typename T> struct Foo { // Class template.
template<typename U> friend void bar(Foo, Foo<U> f) { // Friend function template, defined inline.
static_cast<void>(f.private_field); // Should only compile when T=U.
}
private:
int private_field{};
};
}
int main() {
bar(ns::Foo<char>{}, ns::Foo<char>{}); // Ok.
ns::bar(ns::Foo<char>{}, ns::Foo<char>{}); // (1) FIXME: `ns::bar` not found.
//bar(ns::Foo<bool>{}, ns::Foo<char>{}); // (2): Should fail because bar() here is not a friend of Foo<char>.
}
Я хотел бы иметь возможность вызывать ns::bar<int>(ns::Foo<char>{})
((1)
должен компилироваться) при этом не объявляя о дружбе между bar
call и неродственным Foo<char>
at (2)
. Как мне это сделать?
Если бы Foo
не было шаблоном, я бы объявил template<typename U> void bar(Foo, Foo);
в namespace ns
.
Если бы bar
не был шаблоном (например, с U=char
fixed), я бы объявил его как функцию-шаблон вне класса и поддержал бы его полную специализацию, например здесь : friend void bar<T>(Foo, Foo<char> f);
.
Однако оба являются шаблонами, и у меня нет идей.
UPD: Я пробовал использовать тот же трюк, что и с не-шаблоном bar
, и сделать это шаблон вне класса. Однако похоже, что подружиться с частичной специализацией невозможно.
Моя попытка:
namespace ns {
template<typename T> struct Foo;
template<typename U, typename T> void bar(Foo<T>, Foo<U>);
template<typename T> struct Foo {
template<typename U> friend void bar<U, T>(Foo, Foo<U> f);
// template<typename U, typename TT> friend void bar(Foo<TT>, Foo<U> f); // Compiles, but gives extra friendship to `bar`.
private:
int private_field{};
};
template<typename U, typename T> void bar(Foo<T>, Foo<U> f) {
static_cast<void>(f.private_field); // Should only compile when T=U.
}
}
int main() {
bar(ns::Foo<char>{}, ns::Foo<char>{}); // Ok.
ns::bar(ns::Foo<char>{}, ns::Foo<char>{}); // (1) FIXME: `ns::bar` not found.
//bar(ns::Foo<bool>{}, ns::Foo<char>{}); // (2): Should fail because bar() here is not a friend of Foo<char>.
}
Вывод G CC:
x.cpp:7:38: error: invalid use of template-id 'bar<U, T>' in declaration of primary template
7 | template<typename U> friend void bar<U, T>(Foo, Foo<U> f);
| ^~~~~~~~~
x.cpp: In instantiation of 'void ns::bar(ns::Foo<T>, ns::Foo<U>) [with U = char; T = char]':
x.cpp:19:41: required from here
x.cpp:14:25: error: 'int ns::Foo<char>::private_field' is private within this context
14 | static_cast<void>(f.private_field); // Should only compile when T=U.
| ~~^~~~~~~~~~~~~
x.cpp:10:9: note: declared private here
10 | int private_field{};
| ^~~~~~~~~~~~~