C++ref-qualifier(引用限定符)
,特别是在类似棋盘ChessBoard的场景下访问棋子时,如何根据对象是左值/右值或const/非const
来返回不同类型的引用。
1⃣
基本棋盘类访问函数
structChessBoard{ChessPieceboard[64];//
8x8
constChessPiece&at(std::size_t
row,std::size_t
col)&{std::cout<<"lvalue
non-const\n";returnboard[8*row+col];}//
左值对象,constChessPiececonst&at(std::size_t
row,std::size_t
col)const&{std::cout<<"lvalue
const\n";returnboard[8*row+col];}//
右值对象,非
constChessPiece&&at(std::size_t
row,std::size_t
col)&&{std::cout<<"rvalue
non-const\n";returnstd::move(board[8*row+col]);}//
右值对象,constChessPiececonst&&at(std::size_t
row,std::size_t
col)const&&{std::cout<<"rvalue
const\n";returnstd::move(board[8*row+col]);}};
解释
- ref-qualifier
&/&&
&表示只能在左值对象上调用&&表示只能在右值对象上调用
ChessBoard,只读移动引用(很少用)cb;cb.at(0,0);//
&
版本ChessBoard{}.at(0,0);//
&&
修饰符
const→&
const
constChessBoard,只读ccb;ccb.at(0,0);//
const
版本std::move(ccb).at(0,0);//
const
start="3">
返回值选择
- 左值非
const
返回
ChessPiece&,可以修改棋子- 左值
const
const&
右值非 const
返回
ChessPiece&&,可以移动棋子右值 const
const&&
2⃣
为什么要用这种写法?
- 匹配对象的值类别(左值/右值)
- 匹配对象的const
属性
- 避免不必要的拷贝
- 利用右值引用支持move
semantics
3⃣C++23
auto&&)
C++23
支持成员模板写法:
auto&&at(thisauto&&self,std::size_trow,std::size_t
col){returnstd::forward<decltype(self)>(self).board[8*row+col];}
解释
this→auto&&
self
self会根据调用对象的值类别自动推导为:ChessBoard&→const&→
const
ChessBoard&&→const
std::forward<decltype(self)>(self)→完美转发,保证:
- 左值返回左值引用
- 右值返回右值引用
- 返回类型
auto&&→完美引用,自动匹配值类别和
对应数学表示
假设棋盘数组:
=
b_{7,7}]boa
style="margin-right:
0.0278em;">r
d=[bstyle="height:
0.05em;">0,0
style="height:
0.2861em;">
,bstyle="height:
0.05em;">0,1
style="height:
0.2861em;">
,...,bstyle="height:
0.05em;">7,7
style="height:
0.2861em;">
]/>行列访问公式:
col]boa
style="margin-right:
0.0278em;">r
d[rostyle="margin-right:
0.0269em;">w
∗8+costyle="margin-right:
0.0197em;">l
]=
\end{cases}at(ro
style="margin-right:
0.0269em;">w
,costyle="margin-right:
0.0197em;">l
)=style="height:
-1.6em;">⎩
style="top:
preserveaspectratio="xMinYMin">
style="top:
-3.15em;">⎨
style="top:
preserveaspectratio="xMinYMin">
style="top:
-5.2em;">⎧
style="height:
2.45em;">
style="height:
0.0715em;">C
hessstyle="margin-right:
0.1389em;">P
iece&style="top:
-3.69em;">const
style="margin-right:
0.0715em;">C
hessstyle="margin-right:
0.1389em;">P
iece&style="top:
0.0715em;">C
hessstyle="margin-right:
0.1389em;">P
iece&&style="top:
-0.81em;">const
style="margin-right:
0.0715em;">C
hessstyle="margin-right:
0.1389em;">P
iece&&style="height:
2.63em;">
style="height:
-5.13em;">左值非const
style="top:
-3.69em;">左值const
style="top:
-2.25em;">右值非const
style="top:
-0.81em;">右值const
style="height:
2.63em;">
5⃣
cb;constChessBoard
ccb;cb.at(0,0);//
lvalue
non-constccb.at(0,0);//
lvalue
conststd::move(cb).at(0,0);//
rvalue
non-conststd::move(ccb).at(0,0);//
rvalue
版本cb.at(1,1);//
自动推导
完美转发std::move(cb).at(1,1);//
自动推导
完美转发
控制台输出:
lvalue+non-const
总结
- ref-qualifier(
&/&&)可以根据对象值类别重载成员函数
- const决定是否可以修改对象
- C++23
auto&&
auto&&返回类型自动推导值类别
完美引用,代码简洁、可维护
- ref-qualifier(
- 访问棋盘公式统一:
board[row*8+
/>
https://godbolt.org/z/Po9h58cjd
1⃣
数据结构定义
structChessPiece{std::stringname;};
- 定义了一个
ChessPiece结构体,表示棋子。 - 里面只有一个成员
name,用于存储棋子的名称(比如“Pawn”,
等)。
structChessBoard{ChessPieceboard[64];//
8x8
棋盘
ChessBoard是棋盘类,用一个一维数组board[64]存储棋子。- 8x8
/>index
=
\text{col}index=8×row+col
2⃣
四种成员函数重载(传统写法)
C++11/14/17
member
functions,可以根据对象的左值/右值和
const
修饰选择不同的函数。
//左值非
const
ChessPiece&at(std::size_trow,std::size_t
col)&{std::cout<<"lvalue
non-const\n";returnboard[8*row+col];}
&表示只能作用于左值对象。- 返回可修改的引用,可以修改棋盘内容。
- 调用例:
cb.at(0,0)
//const
ChessPiececonst&at(std::size_trow,std::size_t
col)const&{std::cout<<"lvalue
const\n";returnboard[8*row+col];}
const&表示只能作用于const
左值
。- 返回const
引用
,不可修改棋子。 - 调用例:
ccb.at(0,0)
//右值非
const
ChessPiece&&at(std::size_trow,std::size_t
col)&&{std::cout<<"rvalue
non-const\n";returnstd::move(board[8*row+col]);}
&&表示只能作用于右值对象。- 返回右值引用,允许移动语义。
- 调用例:
std::move(cb).at(0,1)
//const
ChessPiececonst&&at(std::size_trow,std::size_t
col)const&&{std::cout<<"rvalue
const\n";returnstd::move(board[8*row+col]);}
const&&表示只能作用于右值且const
对象
。- 返回const
rvalue
引用
,可以移动但不可修改内容。 - 调用例:
std::move(ccb).at(0,1)
✓
+
种组合。
- 定义了一个
- 可以精确控制函数调用和返回类型,提高效率。
- 特别适合带移动语义的类型(如
std::string、std::vector)。
3⃣
auto&&统一写法
auto&&at23(thisauto&&self,std::size_trow,std::size_t
col){std::cout<<"C++23
this
version\n";returnstd::forward<decltype(self)>(self).board[8*row+col];}
this是C++23auto&&
self
新特性
,把this当作普通参数。- 优势:
- 无需写四个重载函数。
- 自动根据调用对象类型(左值/右值、const/非
const)完美转发。
std::forward<decltype(self)>(self)保证:- 左值调用
返回引用
- 右值调用
返回右值引用
- 左值调用
调用示例:
cb.at23(1,0);//左值非
const
ccb.at23(1,0);//const
std::move(cb).at23(1,1);//右值非
const
std::move(ccb).at23(1,1);//const
所有情况都只需要一个函数即可处理。
4⃣
主函数分析
ChessBoardcb;constChessBoard
ccb;cb.board[0].name="Pawn";cb.board[1].name="Knight";
- 创建普通棋盘
cb和const
棋盘
ccb。 - 给
cb设置棋子名称。 - 测试四种重载和
C++23
新特性。
cb.at(0,0);//输出:
non-const
ccb.at(0,0);//输出:
const
std::move(cb).at(0,1);//输出:
non-const
std::move(ccb).at(0,1);//输出:
const
- 四种传统重载清晰展示调用规则。
- C++23
版本:
cb.at23(1,0);ccb.at23(1,0);std::move(cb).at23(1,1);std::move(ccb).at23(1,1);- 统一函数
自动完美转发。
- 输出都是:
C++23this
/>
特性 调用对象 返回类型 说明 ChessPiece&at()
const
左值引用 可修改棋子 constChessPiece&
左值引用
只读棋子 ChessPiece&&at()
const
右值引用 可移动棋子 constChessPiece&&
const&&
右值 const
const 右值引用
可移动但只读棋子 auto&&at23(this
auto&&)
任意对象 完美转发引用 C++23 统一写法,自动适应左值/右值、const
/>
- 数学公式表示下标计算:
/>board[row][col]
=
col]board[row][col]=board[8⋅ro
style="margin-right:
0.0269em;">w
+costyle="margin-right:
0.0197em;">l
] - 完美转发公式(C++23):
/>return
type
std::forward<decltype(self)>(self).board[index]return
type=decltype(auto)ofstd::
style="margin-right:
0.0269em;">w
astyle="margin-right:
0.0278em;">r
d<decltstyle="margin-right:
0.0359em;">y
pe(sestyle="margin-right:
0.1076em;">f
)>(sestyle="margin-right:
0.1076em;">f
).boastyle="margin-right:
0.0278em;">r
d[index]
- 数学公式表示下标计算:


