友元、模板、命名空间
friend, template, namespace
我想要一个模板化的好友功能。但是,我不知道如何使它在没有模板化功能的情况下以相同的方式工作。
这是一个示例代码
#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
是模板的名称,以便它知道 <
开始一个模板参数列表,而不是 less-比运算符:
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;
}
我想要一个模板化的好友功能。但是,我不知道如何使它在没有模板化功能的情况下以相同的方式工作。 这是一个示例代码
#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
是模板的名称,以便它知道 <
开始一个模板参数列表,而不是 less-比运算符:
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;
}