item 1
函数参数可以声明为数组的引用:
const char name[] = "J. P. Briggs"; // name's type is const char[13]
//T推导出来的实际类型是数组, 类型推导包括了数组的长度
template <typename T> void f(T ¶m)
{
cout << sizeof(param) << endl; //13
}
//T推导出来的实际类型是const char *
template <typename T> void f2(T param)
{
cout << sizeof(param) << endl; // 4 or 8
}
声明数组的引用使得可以创造出一个推导出数组元素数量的模板:
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept
{
return N;
}
//再比如std::end对数组的特化
template <class T, size_t N>
T* end(T(&arr)[N])
{
return arr + N;
}
item 4
让编译器指示decltype推导出来的类型:
template <typename T>
class TD;
int main()
{
int x;
TD<decltype((x))> xType;
return 0;
}
错误消息类似error: aggregate 'TD<int&> xType' has incomplete type and cannot be defined。
item 12
成员函数的引用修饰符使得这些函数只能被左值或右值引用:
class Widget
{
public:
void doWork() &; // this version of doWork applies, only when *this is an lvalue
void doWork() &&; // this version of doWork applies, only when *this is an rvalue
};
Widget makeWidget(); // factory function (returns rvalue)
Widget w; // normal object (an lvalue)
w.doWork(); // calls Widget::doWork for lvalues
makeWidget().doWork(); // calls Widget::doWork for rvalues
item 15
const是readonly的意思。
所有constexpr对象都是const的,但不是所有const对象都是constexpr的。
如果你想编译器保证一个变量有一个可以放到那些需要编译期常量的上下文的值,你需要的工具是 constexpr 而不是 const。
如果使用场景涉及函数,那 constexpr 就更有趣了。如果实参是编译期常量,它们将产出编译期值;如果是运行时值,它们就将产出运行时值。
我的理解是,constexpr 函数帮助编译器把一些可以在编译期进行的计算放到编译期来做。还挺麻烦的,平常也没多大必要使用。
item 31
lambda只能捕获所在作用域里的非静态局部变量或函数参数。全局变量或静态局部变量,无需捕获便可使用。