作者LPH66 (かつて交わした约束)
看板C_and_CPP
标题[心得] 运算子覆载 (was: Re: [问题] 初值阵列...)
时间Wed Apr 5 18:03:28 2017
原 PO 的问题已经离原标题很远了所以改个标题
而且其实搞懂这边对最一开始的问题并没有帮助所以 (ry
: (参考实作可看
: http://en.cppreference.com/w/cpp/types/integral_constant
: 下面 Possible implementation 那里)
: → hunandy14: 看了好久还是不能理解QQ 容我一个一个问麽 04/03 22:31
: → hunandy14: std::integral_constant 里面的 04/03 22:33
: → hunandy14: operator value_type() 这是什麽功用算是operator吗 04/03 22:34
: → LPH66: 那是转型用, 是在需要一个这种物件实体时才要的 04/04 02:22
: → LPH66: 跟本文的编译时期常数无关 04/04 02:22
: → LPH66: operator() 也是一样, 是在需要一个 functor 时才要的 04/04 06:35
: 推 hunandy14: Possible implementation 那里 提到的 size_t 04/04 17:31
: → hunandy14: 连结到网页内怎麽没发现这个~ 04/04 17:32
: → hunandy14: 我也顺便去看了 functor 想请问那两个有什麽差异~ 04/04 17:33
: → hunandy14: operator value_type() || value_type operator()() 04/04 17:34
: → hunandy14: 然後为什麽 op 名称还可以带 value_type 字样~ 04/04 17:35
: → hunandy14: 看到的用法都是直接 operator() 04/04 17:36
你这里把好几个长得很像但实际上不太一样的语法给全部混在一起了
不过虽然实际上不太一样, 它们还是有个共同点就是都是运算子覆载
一般来说, 运算子覆载的语法是
回传型态 operator 运算子 (参数) {...}
相信你应该知道 operator + 之类的覆载要怎麽写, 这里就不重覆了
这里要提的是两种比较特别的运算子覆载
====
1. operator ()
它覆载的运算子就是长成一对小括号
至於什麽运算子是小括号? 就是函数呼叫
也就是说, 这是覆载拿这个物件当做函数名来呼叫时的行为
具有这种特性的物件我们称做 functor, 或是 function object
中文可以叫做「函式物件」, 一些细节部份就请参照维基百科:
https://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E5%AF%B9%E8%B1%A1
这里可以注意到因为 "operator ()" 是被覆载的运算子名称
所以实际上在定义里会有两组小括号并排, 像是上面例子里的
bool operator()(const int &a, const int &b) const
这种东西的用途有点类似 Strategy pattern
把一些演算法里的关键部份抽出来使其可以自订
这样同一套演算法就能用在很多不同地方
如维基百科条目所言, <algorithm> 的众多演算法依赖於这种东西做处理
<functional> 里也有定义了许多预先定义的小函数可以使用
====
2. 转型运算子
是的, 转型也是一个单元运算子
一般来说, 对於物件型态之间的转型有两个可以定义的方向
常见的是目标方定义, 就是在转向的目标类别里定义建构子
例如
class Foo
{
public:
Foo(Bar bar) {...} //一个 Bar 物件转成一个 Foo 物件
};
这里要提的则是来源方定义, 表示我这物件要转成这型态时要怎麽办
它的语法是在运算子覆载的语法里, 在运算子那个位置摆上目标型态
然後不要写回传型态 (因为就一定是目标型态了)
也不要加参数 (转型就是物件本身转过去所以不会有参数)
例如
class Bar
{
public:
operator Foo () {...} //一个 Bar 物件转成一个 Foo 物件
operator int () {...} //一个 Bar 物件转成一个 int
};
那因为是目标型态所以任何代表一个型态的名字都能放在那里
像是上例的 Foo 或是 typedef 来的名字如你问的 value_type 等等
====
然後, 还是简单拉回到 std::integral_constant
template<class T, T v>
struct integral_constant {
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type; // using injected-class-name
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
value 是值, value_type 和 type 是 typedef 名这个应该不用多说
operator value_type() 定义一个 integral_constant<T> 物件如何转成 value_type
operator () 定义一个 integral_constant<T> 物件当做函数呼叫时回传其值
这两个就是上面提的两种运算子覆载
不过这两种都是需要一个这个物件实体才能进行的动作
和前文在讨论的编译时期常数 (用来宣告阵列大小) 是完全无关的
--
1985/01/12 三嶋鸣海 1989/02/22 优希堂悟 1990/02/22 冬川こころ 1993/07/05 小町
つぐみ 欢迎来到 1994/05/21 高江ミュウ 1997/03/24 守野いづみ 1997/03/24 伊野瀬
チサト 1998/06/18 守野くるみ 打越钢太郎的 1999/10/19 楠田ゆに 2000/02/15 樋口遥
2002/12/17 八神ココ 2011/01/11 HAL18於朱仓岳坠机 ∞与∫的世界 2011/04/02 茜崎空
启动 2012/05/21 第貮日蚀计画预定 2017/05/01~07 LeMU崩坏 2019/04/01~07 某大学合宿
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.112.30.32
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1491386611.A.4DA.html
1F:推 hunandy14: 非常感谢~ 04/05 23:16
2F:→ hunandy14: 我理解的套路是~tuple_size继承了 04/05 23:20
3F:→ hunandy14: integral_constant 并在初始化时透过sizeof...给长度 04/05 23:21
4F:→ hunandy14: 然後因为他有value 使得可以 t_s::v 能够返回出长度 04/05 23:23
5F:→ hunandy14: 哦 所以你才会说 op 这里没影响到我的问题 04/05 23:24
6F:推 hunandy14: 如果我把它实作出一个物件,我要怎麽取得值 04/05 23:34
7F:→ hunandy14: 一样直接 :: 取得吗? 像这样 04/05 23:35
8F:→ hunandy14: integral_constant<int, 2> a; 04/05 23:35
9F:→ hunandy14: cout << a::value << endl; 如此一来就会触发倒数2行吗 04/05 23:36
10F:→ hunandy14: operator value_type() 04/05 23:37
11F:→ hunandy14: 测试一下并不是我想得这样QQ 能够举个例子触发他们吗~ 04/05 23:57
12F:→ LPH66: 文中都说了, 一个是转型一个是当函数呼叫 04/06 00:24
13F:→ LPH66: 转型那个是 (int)a (因为 a 的 value_type 是 int) 04/06 00:24
14F:→ LPH66: 呼叫则是 a() 04/06 00:25
15F:→ LPH66: a::value 就一样只是取 value 那个成员而已 04/06 00:25
16F:推 ACMANIAC: 推 打越粉! 04/06 05:00
17F:→ hunandy14: 没想到~ 了解 04/06 12:08