目录
std::declval
返回左值引用还是返回右值引用
class A { public: A(int i) //构造函数 { printf("A::A()函数执行了,this=%p\n", this); } double myfunc() //普通成员函数 { printf("A::myfunc()函数执行了,this=%p\n", this); return 12.1; } private: ~A() {} }; template <typename T> T& mydeclval() noexcept;
- 调用
using boost::typeindex::type_id_with_cvr; cout << "decltype(mydeclval<A>)())的返回类型=" << type_id_with_cvr<decltype(mydeclval<A>())>().pretty_name() << endl; cout << "decltype(mydeclval<A&>)())的返回类型=" << type_id_with_cvr<decltype(mydeclval<A&>())>().pretty_name() << endl; cout << "decltype(mydeclval<A&&>)())的返回类型=" << type_id_with_cvr<decltype(mydeclval<A&&>())>().pretty_name() << endl;
- 输出(用到了引用折叠)
decltype(mydeclval<A>)())的返回类型 = class A & decltype(mydeclval<A&>)())的返回类型 = class A & decltype(mydeclval<A&&>)())的返回类型 = class A &
将mydeclval返回改成右值引用
template <typename T> T&& mydeclval() noexcept;
- 输出(用到了引用折叠)
decltype(mydeclval<A>)())的返回类型 = class A && decltype(mydeclval<A&>)())的返回类型 = class A & decltype(mydeclval<A&&>)())的返回类型 = class A &&
- 通过上面两种方式对比可知:设定返回为右值引用,可以获得更多的类型,而设定返回左值应用不论传入什么类型的参数,返回全部的都是左值引用。
调用引用限定符修饰的成员函数范例
class ALR { public: void onAnyValue() { cout << "ALR::onAnyValue()函数执行了!" << endl; } void onLvalue()& //只能被类ALR的左值对象调用 { cout << "ALR::onLvalue()函数执行了!" << endl; } void onRvalue()&& //只能被类ALR的右值对象调用 { cout << "ALR::onRvalue()函数执行了!" << endl; } }; template <typename T> T&& mydeclval() noexcept;
- 调用1
ALR alr; //左值对象alr alr.onLvalue(); //alr.onRvalue(); //编译错误,因为onRvalue只能被类A的右值对象调用 ALR().onRvalue(); //临时对象是右值对象 //ALR().onLvalue(); //编译错误,因为onLvalue只能被类A的左值对象调用
- 调用2
decltype(mydeclval<ALR>().onAnyValue()); decltype(mydeclval<ALR&>().onLvalue()); //返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onLvalue没问题 decltype(mydeclval<ALR&&>().onRvalue()); //返回的 类型是class ALR &&,代表返回的是右值对象,右值对象调用onRvalue没问题 //decltype(mydeclval<ALR&>().onRvalue());//返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onRvalue是错误的 //decltype(mydeclval<ALR&&>().onLvalue()); //返回的 类型是class ALR &&,代表返回的是右值对象,右值对象调用onLvalue是错误的
将mydeclval返回改成左值引用
template <typename T> T&& mydeclval() noexcept;
- 调用
decltype(mydeclval<ALR>().onAnyValue()); decltype(mydeclval<ALR&>().onLvalue()); //返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onLvalue没问题 //decltype(mydeclval<ALR&&>().onRvalue()); //返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onRvalue是错误的 //decltype(mydeclval<ALR&>().onRvalue());//返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onRvalue是错误的 decltype(mydeclval<ALR&&>().onLvalue()); //返回的 类型是class ALR &,代表返回的是左值对象,左值对象调用onLvalue没问题
推导函数返回值范例
int myfunc(int a, int b) //函数类型一般是由函数的返回值和参数类型决定,与函数名没有关系,所以myfunc代表的函数类型是: int(int,int); { return a + b; } template<typename T_F, typename... U_Args> decltype(std::declval<T_F>() (std::declval<U_Args>()...)) TestFnRtnImpl(T_F func, U_Args... args) { auto rtnvalue = func(args...); return rtnvalue; }
- T_F:是int (*)(int,int)类型,也就是函数指针类型
- decltype(std::declval<T_F>() (std::declval<U_Args>()...)):是int类型,也就是myfunc函数的返回类型
- a)decltype(std::declval<T_F>() ):是 int (* && )(int,int),函数指针的右值引用类型,其实就简单理解成函数指针类型
int (*fp_var)(int x, int y); //函数指针类型fp_var = int(*)(int,int) int (* &&yy_fp_var)(int x, int y) = std::move(fp_var); //函数指针的右值引用yy_fp_var = int(* &&)(int,int),现在yy_fp_var就可以代表fp_var fp_var = _nmsp2::myfunc; cout << fp_var(1, 2) << endl; //3 cout << yy_fp_var(1, 2) << endl; //3
- b)decltype(std::declval<U_Args>()...)这种写法:推导出来的是两个int &&
- 返回值推导若写成:decltype(T_F(U_Args...)) TestFnRtnImpl(T_F func, U_Args... args)
- 报错:decltype不是这么用的,decltype后面圆括号中出现的一般都是变量、对象、表达式、函数名、函数指针名等等。
- 调用
uto result = TestFnRtnImpl(myfunc, 5, 8); //T_F被推断出 int(*)(int,int) //或者指定T_F类型 auto result1 = TestFnRtnImpl<int(int,int)>(myfunc, 5, 8); cout << result << endl; //13
【auto + decltype 后置语法方式】
template<typename T_F, typename... U_Args> auto TestFnRtnImpl2(T_F func, U_Args... args)->decltype(func(args...)) //decltype(func(args...)):int类型,也就是myfunc的返回类型。 //decltype(func):int(*)(int,int)类型,函数指针类型 { auto rtnvalue = func(args...); return rtnvalue; }
- 调用
auto result2 = TestFnRtnImpl2(myfunc, 13, 15); cout << result2 << endl; //28