C++ 中的函数模板特化和右值引用
Function template specialization and rvalue reference in c++
#include <iostream>
struct Cls{double dval = 0;};
template<typename T>
void foo(T&& Obj) {
//..... use Obj
}
void foo(const Cls& Obj) {
//..... use Obj.dval
}
//void foo(Cls Obj) {
// //..... use Obj.dval
//}
int main()
{
Cls Obj;
const Cls cv_Obj;
foo(Obj); //case 1
foo(Cls{}); //case 2
foo(cv_Obj); //case 3
foo(10.10);
}
如果函数参数是 const ref
,Cls
的模板特化失败 (case 1, case 2
),但 by val
适用于所有情况。
除了 pass by val
之外,还有其他方法可以处理所有 cases
(所有值类型)的专业化吗?
您可以使用 SFINAE 解决此问题,但摆脱 _struct
上的重载并为 operator<<
:
定义重载会容易得多
std::ostream& operator<<(std::ostream& os, const _struct& obj)
{
os << obj.dval;
return os;
}
用 SFINAE 解决的一种可能性是在一个重载中直接检查输出 Obj
的有效性,并在另一个重载中检查 _struct
的类型:
template<typename T>
auto foo(T&& Obj) -> decltype(std::cout<<Obj, void()) {
std::cout<<Obj;
}
template<typename T,
std::enable_if_t<std::is_same<_struct, std::decay_t<T>>::value>* = nullptr>
void foo(T&& Obj) {
std::cout<<Obj.dval;
}
你需要一个辅助结构:
#include <iostream>
struct _struct{double dval = 0;};
template<typename T, typename Enable = void>
struct bar {
bar(T&& Obj) {
std::cout<<Obj;
}
};
template<typename T>
struct bar<T, typename std::enable_if<std::is_same<typename std::decay<T>::type, _struct>::value>::type> {
bar(T&& Obj) {
std::cout<<Obj.dval;
}
};
template<typename T>
void foo(T&& Obj) {
bar<T>(std::forward<T>(Obj));
}
int main()
{
_struct Obj;
const _struct cv_Obj;
foo(1);
foo(Obj); //case 1
foo(_struct{}); //case 2
foo(cv_Obj); //case 3
foo("test");
}
#include <iostream>
struct Cls{double dval = 0;};
template<typename T>
void foo(T&& Obj) {
//..... use Obj
}
void foo(const Cls& Obj) {
//..... use Obj.dval
}
//void foo(Cls Obj) {
// //..... use Obj.dval
//}
int main()
{
Cls Obj;
const Cls cv_Obj;
foo(Obj); //case 1
foo(Cls{}); //case 2
foo(cv_Obj); //case 3
foo(10.10);
}
如果函数参数是 const ref
,Cls
的模板特化失败 (case 1, case 2
),但 by val
适用于所有情况。
除了 pass by val
之外,还有其他方法可以处理所有 cases
(所有值类型)的专业化吗?
您可以使用 SFINAE 解决此问题,但摆脱 _struct
上的重载并为 operator<<
:
std::ostream& operator<<(std::ostream& os, const _struct& obj)
{
os << obj.dval;
return os;
}
用 SFINAE 解决的一种可能性是在一个重载中直接检查输出 Obj
的有效性,并在另一个重载中检查 _struct
的类型:
template<typename T>
auto foo(T&& Obj) -> decltype(std::cout<<Obj, void()) {
std::cout<<Obj;
}
template<typename T,
std::enable_if_t<std::is_same<_struct, std::decay_t<T>>::value>* = nullptr>
void foo(T&& Obj) {
std::cout<<Obj.dval;
}
你需要一个辅助结构:
#include <iostream>
struct _struct{double dval = 0;};
template<typename T, typename Enable = void>
struct bar {
bar(T&& Obj) {
std::cout<<Obj;
}
};
template<typename T>
struct bar<T, typename std::enable_if<std::is_same<typename std::decay<T>::type, _struct>::value>::type> {
bar(T&& Obj) {
std::cout<<Obj.dval;
}
};
template<typename T>
void foo(T&& Obj) {
bar<T>(std::forward<T>(Obj));
}
int main()
{
_struct Obj;
const _struct cv_Obj;
foo(1);
foo(Obj); //case 1
foo(_struct{}); //case 2
foo(cv_Obj); //case 3
foo("test");
}