说明
以下内容均指C++ 11中的特性, 主要包括Effective Modern C++这本书英文原版中涉及到模板类型推导规则的部分(Chapter 1以及Item 28)
模板类型推导要点
- 可以进行取地址操作的都是lvalue, 即使声明为T&& 类型的变量,例如
const int&& int_rr=5;
int_rr是lvalue
不能进行取地址操作的均为rvalue, 例如临时变量和常数
模板中形如T&&的为universal reference, universal reference可以转发lvalue也可以转发rvalue, 因此, 转发parameter pack一般使用以下形式, 例如,以下递归求N个字符串长度的模板函数
template<typename String, typename... Rest>
struct concatenate_impl<String, Rest...> {
static size_t size(String&& s, Rest&&... rest) {
return string_size(s)
+ concatenate_impl<Rest...>::size(std::forward<Rest>(rest)...);
}
static void concatenate(std::string& result, String&& s, Rest&&... rest) {
result += s;
concatenate_impl<Rest...>::concatenate(result, std::forward<Rest>(rest)...);
}
};
- 模板函数参数传引用T& 可以匹配数组(可以包括长度信息), 而按值传递T只能匹配T*(没有长度信息), 例如以下函数
// return size of an array as a compile-time constant. (The
// array parameter has no name, because we care only about
// the number of elements it contains.)
template<typename T, std::size_t N> // see info
constexpr std::size_t arraySize(T (&)[N]) noexcept // below on
return N; // and
} // noexcept
- 模板函数参数传值T会去掉 CV属性和reference, 传引用T&不会
- 模板递归实例化过程中如果出现“引用的引用”, reference collasping会发生,简单说就是模板实例化(用户代码中不能显式声明引用的引用类型的变量)过程中多个引用叠加的话如果其中一个是lvalue reference, 那么替换结果为lvalue reference,否则为rvalue reference
测试代码
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
template <class T> struct add_ref{
typedef T& ref_type;
};
const int& int_r=5;
template <class T> void test_param_ref(T& param){
using std::cout;
using boost::typeindex::type_id_with_cvr;
// show T
cout << "T = "
<< type_id_with_cvr<T>().pretty_name()
<< '\n';
// show param's type
cout << "param = "
<< type_id_with_cvr<decltype(param)>().pretty_name()
<< '\n';
}
template <class T> void test_param_rref(T&& param){
using std::cout;
using boost::typeindex::type_id_with_cvr;
// show T
cout << "T = "
<< type_id_with_cvr<T>().pretty_name()
<< '\n';
// show param's type
cout << "param = "
<< type_id_with_cvr<decltype(param)>().pretty_name()
<< '\n';
}
template <class T> void test_param_val(T param){
using std::cout;
using boost::typeindex::type_id_with_cvr;
typedef typename add_ref<T>::ref_type ref_type;
// show ref_type
cout << "add_ref type = "
<< type_id_with_cvr<ref_type>().pretty_name()
<< '\n';
// show T
cout << "T = "
<< type_id_with_cvr<T>().pretty_name()
<< '\n';
// show param's type
cout << "param = "
<< type_id_with_cvr<decltype(param)>().pretty_name()
<< '\n';
}
int main()
{
using std::cout;
using std::endl;
cout << "test param passed by value" << endl;
test_param_val(int_r);
cout << endl;
cout << "test param passed by ref" << endl;
test_param_ref(int_r);
cout << endl;
cout << "test lvalue passed by rvalue ref" << endl;
test_param_rref(int_r);
cout << endl;
cout << "test rvalue passed by rvalue ref" << endl;
test_param_rref(6);
}
输出
test param passed by value
add_ref type = int&
T = int
param = int
test param passed by ref
T = int const
param = int const&
test lvalue passed by rvalue ref
T = int const&
param = int const&
test rvalue passed by rvalue ref
T = int
param = int&&