好友、模板、命名空间

friend, template, namespace

本文关键字:命名空间 模板 好友      更新时间:2023-10-16

我想要一个模板化的友元函数。但是,我不知道如何使其在没有模板化功能的情况下以相同的方式工作。 下面是一个示例代码

#include <iostream>
namespace ns{
struct Obj {
friend void foo(Obj){std::cout << "no problem" << std::endl;}
template<typename T>
friend void bar(Obj){std::cout << "problem" << std::endl;}
};
}
int main() {
ns::Obj obj;
foo(obj); // Compile
bar<int>(obj); // Not compile
return 0;
}

> 在 C++20 之前,您需要告诉编译器bar是模板的名称,以便它知道<启动模板参数列表并且不是小于运算符:

template<char> void bar() = delete;
int main() {
ns::Obj obj;
foo(obj); // Compile
bar<int>(obj); // Now compiles too
return 0;
}

请注意,重载bar要做的就是成为函数模板。签名无关紧要,只要它不是好到干扰重载分辨率;()是一个不错的选择,因为根据定义,我们至少传递一个参数,因此不带参数的函数模板永远不可行。

或者,您可以重新设计bar以从标记参数推断T

template<class T>
struct type {};
namespace ns{
struct Obj {    
// ...
template<typename T>
friend void bar(Obj, type<T>) { /* ... */ }
};
}
// ...
bar(obj, type<int>()); // OK

在 C++20 中,编译器将假定bar在看到模板时命名模板<并且名称查找未找到任何内容,因此您的代码将正常工作

直接的方法是添加一个前向声明,并让使用限定查找来定位函数:

namespace ns{
struct Obj;
void foo(Obj);
template<typename T>
void bar(Obj);
struct Obj {
friend void foo(Obj){std::cout << "no problem" << std::endl;}
template<typename T>
friend void bar(Obj){std::cout << "problem " << std::endl;}
};
} // namespace ns
int main() {
ns::Obj obj;
ns::foo(obj); // Ok
ns::bar<int>(obj); // Ok
return 0;
}