在函數返回值/range-for 等情況中
1、auto使用 有5種用法
auto :拷貝
auto& :左值引用,只能接左值(和常量右值)
auto&& :萬能引用,能接左值和右值
const auto& :const 萬能引用,能接左值和右值
const auto&& :常量右值引用,只能接右值
很多人直接就寫成 auto&&,但儘量分場景使用
auto:用於你想修改右值的情形
auto&:用於你想修改左值的情形
auto&&:用於泛型編程中的轉發
const auto&:用於只讀
const auto&&:基本沒用,基本可被 const auto& 替代(比 const auto& 多一個語義:一定得是右值。然而這沒什麼用,因爲你都不對其進行修改,是左還是右沒什麼影響)
2、返回值自動推導,增強模板的泛型能力
//C++11
template<typename T1, typename T2>
auto sum(T1&& x, T2&& y) -> decltype(x + y) {
return x + y;
}
// C++14:
template<typename T1, typename T2>
auto sum(T1&& x, T2&& y) {
return x + y;
}
3、泛型Lambda
// C++14;
auto mul = [](const auto x, const auto y) { return x * y; };
4、decltype(auto)推導保留cv:
// C++14;
template<typename T, typename I>
decltype(auto) accessVector(T&& c, I i) { return c[i]; } // 返回 int&;
int main(int argc, char** argv) {
std::vector<int> v = {0};
accessVector(v, 0) = 10000;
std::cout << v.at(0) << std::endl; // 10000;
return 0;
}
5、做Perfect Forwarding 中對{}表達式的中轉
void foo(std::vector<int> v) {
for (const auto& i : v) { std::cout << i << std::endl; }
}
template<typename ...Arg>
void forwardFunc(Arg&& ...args) {
foo(std::forward<Arg...>(args...));
}
int main(int argc, char** argv) {
auto il = {1, 2, 3};
forwardFunc(il);
return 0;
}
6、簡化函數指針寫法
int(*(*foo)())() {};
auto foo() -> auto (*)() -> int(*)() {}; // 與上述等價;
需要注意的幾個坑
1、STL 代理類型導致 auto 可能推導出並非自己想要的類型:
// 主要源於 std::vector 在存儲布爾元素時的特殊方式;
int main(int argc, char** argv) {
std::vector<bool> v ={ true };
auto x = v.at(0); // std::vector<bool>::reference, not bool;
return 0;
}
2、auto 在推導 List Initialization 表達式時的默認類型(std::initializer_list)
int main(int argc, char** argv) {
auto l = {1, 2, 3}; // std::initializer_list<int>;
}