備忘録です
(どのサイトにも似たような説明が書かれているので、詳細は省きます)
(結果はバージョンやコンパイラーによって変わる場合があります)
autoが記述できる場所
.cpp
#include <iostream>
auto f1() { return 1; } //戻り値型
int f2(auto a) { return a; } //引数型
auto f3(int a) -> int { return a; } //後置戻り値型のプレースホルダ
auto f4(int a) -> auto { return a; } //後置戻り値型
//f5(),f6()関数の引数が1の場合、
//f5()関数はintが戻り値型となる
//f6()関数はconst int&が戻り値型となる(decltype(auto)の効果)
auto f5(const auto& a) { return a; }
decltype(auto) f6(const auto& a) { return a; }
auto f7 = [](auto a) { return a; }; //ラムダ式の戻り値型と引数型
template<auto T> class A { }; //テンプレートパラメータ
class B {
static inline auto m1 = 1; //OK(staticの場合はautoで変数定義できる)
//auto m2 = 2; //コンパイルエラー(メンバー変数はautoで定義できない)
};
int main()
{
int z = 1;
//auto a; //コンパイルエラー(必ず初期値が必要)
auto b = 1; //変数
decltype(auto) c = z + 1; //右辺の z + 1 がautoの式として使われる
//decltype(z + 1) c = z + 1; //と同じ結果
int* d = new auto(1); //int* d = new int(1) と同じ結果
delete d;
static_assert(std::is_same<decltype(f5(1)), int>::value, "");
static_assert(std::is_same<decltype(f6(1)), const int&>::value, "");
for(auto i = 0; i<3; i++) { std::cout << i << std::endl; }
switch (auto i = f2(99)) {
case 99: std::cout << i << std::endl; break;
default: break;
}
while(auto i = 'c') { std::cout << i << std::endl; break; }
//std::cout << i << std::endl; //コンパイルエラー(当然、ブロック外ではi変数は参照できない)
}
auto と decltype(auto) の違い
.cpp
#include <type_traits>
int main()
{
int z = 1;
auto a = 1;
auto b = (const int) 1;
auto c = (int*) &z;
auto d = (const int*) &z;
auto e = (int&) z;
auto f = (const int&) 1;
auto g = (int&&) 1;
auto h = (const int&&) 1;
//int*はポインタなので*が残るのは当然
//const int*はz変数の値を参照してるのでconstは残る
//const int,int&およびint&&は複製されるのでconstは外れる
static_assert(std::is_same<decltype(a), int>::value, "");
static_assert(std::is_same<decltype(b), int>::value, "");
static_assert(std::is_same<decltype(c), int*>::value, "");
static_assert(std::is_same<decltype(d), const int*>::value, ""); //constは残る
static_assert(std::is_same<decltype(e), int>::value, "");
static_assert(std::is_same<decltype(f), int>::value, "");
static_assert(std::is_same<decltype(g), int>::value, "");
static_assert(std::is_same<decltype(h), int>::value, "");
a = 10;
b = 10;
*c = 10;
//*d = 10; //constなので当然コンパイルエラー
e = 10;
f = 10;
g = 10;
h = 10;
//-----------------------
//-----------------------
decltype(auto) o = 1;
decltype(auto) p = (const int) 1;
decltype(auto) q = (int*) &z;
decltype(auto) r = (const int*) &z;
decltype(auto) s = (int&) z;
decltype(auto) t = (const int&) 1;
decltype(auto) u = (int&&) 1;
decltype(auto) v = (const int&&) 1;
//p変数は複製されるのでconstが外れる
//r,t,v変数は参照なのでconstは残る
static_assert(std::is_same<decltype(o), int>::value, "");
static_assert(std::is_same<decltype(p), int>::value, ""); //constが外れる
static_assert(std::is_same<decltype(q), int*>::value, "");
static_assert(std::is_same<decltype(r), const int*>::value, "");
static_assert(std::is_same<decltype(s), int&>::value, "");
static_assert(std::is_same<decltype(t), const int&>::value, "");
static_assert(std::is_same<decltype(u), int&&>::value, "");
static_assert(std::is_same<decltype(v), const int&&>::value, "");
o = 10;
p = 10;
*q = 10;
//*r = 10; //const
s = 10;
//t = 10; //const
u = 10;
//v = 10; //const
//volatile(C++20より不正確は非推奨), register(C++11より非推奨)の調査は割愛する
}
const,*,&,&&での修飾
.cpp
#include <type_traits>
int main()
{
int z = 1;
const auto* a1 = &z; //autoの前後は修飾できる
const auto& a2 = z;
const auto&& a3 = 1;
auto&& a4 = 1; //auto&&には特別な機能があり、左辺値を代入
auto&& a5 = z; //した場合、左辺値参照になる(a5変数はint&型)
auto b1 = &z; //*で修飾してもしなくても結果は一緒
auto* b2 = &z;
*b1 = 10;
*b2 = 11;
static_assert(std::is_same<decltype(b1), int*>::value, "");
static_assert(std::is_same<decltype(b2), int*>::value, "");
const auto c1 = &z; //constを付けてる場合、微妙に結果が違う
const auto* c2 = &z;
*c1 = 12; //※なぜか変更できる(constが無効になっている)
//*c2 = 13; //constを付けてるので変更できなくて当然
//static_assert(std::is_same<decltype(c1), int*>::value, ""); //c1変数の型がint*でも
//static_assert(std::is_same<decltype(c1), const int*>::value, ""); //const int*でもない(不明な型)
static_assert(std::is_same<decltype(c2), const int*>::value, "");
//-----------------------
//-----------------------
const decltype(auto) d1 = 1; //decltype(auto)の前にconstを付けられる
//decltype(auto*) d2 = &z; //コンパイルエラー(decltype(auto)の後に*,&,&&は付けられない)
//decltype(auto&) d3 = z;
//decltype(auto&&) d4 = 1;
//decltype(auto)* d5 = &z;
//decltype(auto)& d6 = z;
//decltype(auto)&& d7 = 1;
}
参照URL
auto
通常関数の戻り値型推論
decltype(auto)
後置戻り値型をプレースホルダーにすることを許可
ジェネリックラムダ
非型テンプレートパラメータのauto宣言
autoパラメータによる関数テンプレートの簡易定義