std::declval:
声明:
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
将任何一个类型T转换成引用类型,令在decltype表达式中不必经过构造函数就能使用成员函数。
#include <utility>
#include <iostream>
struct Default { int foo() const { return 1; } };
struct NonDefault
{
NonDefault(const NonDefault&) { }
int foo() const { return 1; }
};
int main()
{
decltype(Default().foo()) n1 = 1; // type of n1 is int
// decltype(NonDefault().foo()) n2 = n1; // error: no default constructor
decltype(std::declval<NonDefault>().foo()) n2 = n1; // type of n2 is int
std::cout<< "n1 = " << n1 << '\n'
std::cout<< "n2 = " << n2 << '\n';
}
decltype:
给定一个变量或表达式,decltype能够推导出他的类型。最重要的是能够不需要计算表达式就可以推导出表达式所得值的类型。
如何在模板中使用std::decltype?
在如上的例子中,
decltype(NonDefault().foo()) n2 = n1; // error: no default constructor
decltype在推导一个成员函数的返回值类型时,会报出无默认构造函数的错误。decltype需要一个实例?
再看如下模板中,推导一个函数的返回值:
#include<utility>
#include<iostream>
int test(int a,int b){
int c = a+b;
std::cout<<"Run Test"<<c<<std::endl;
return c;
}
/* 无法通过编译
template<typename Fn, typename... Args>
decltype(Fn(Args...)) test_decltype3(Fn f, Args... args) {
std::cout<<"Run Test_Decltype3"<<std::endl;
auto res = f(args...);
return res;
}
*/
template<typename Fn, typename... Args>
auto test_decltype2(Fn f, Args... args) -> decltype(f(args...)){
std::cout<<"Run Test_Decltype2"<<std::endl;
auto res = f(args...);
return res;
}
template<typename Fn,typename... Args>
decltype(std::declval<Fn>()(std::declval<Args>()...)) test_decltype1(Fn f,Args... args){
std::cout<<"Run Test_Decltype1"<<std::endl;
auto res = f(args...);
return res;
}
int main(int agrc,char *argv[]){
auto res0 = test_decltype1(test,1,2);
auto res1 = test_decltype2(test,1,3);
std::cout<<"Main Res0: "<<res0<<std::endl;
std::cout<<"Main Res1: "<<res1<<std::endl;
return 0;
}
如上看出std::declval 与decltype的用法,在test_decltype1通过std::declval右值引用函数类型及参数类型,完成类型推导。在test_decltype2中通过函数实例及参数实例完成返回值的类型推导。
但是在test_decltype3中,其无法通过编译,decltype需要一个可实例的函子,但是利用std::declval可以避免构造的要求。