我想要一个模板化的朋友功能。但是,我不知道如何让它以相同的方式工作,没有模板化的功能。 这是一个示例代码
#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;
}
答案 0 :(得分:8)
在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
在看到<
并且名称查找找不到任何内容时为模板命名,因此您的代码将正常工作
答案 1 :(得分:4)
直接的方法是添加前向声明,并使用限定查找来定位函数:
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;
}