Skip to content

Commit fa85c97

Browse files
committed
文章更新
1 parent 61f5685 commit fa85c97

File tree

19 files changed

+335
-274
lines changed

19 files changed

+335
-274
lines changed

docs/ProgrammingBlog/Cyan/TypingSystem/article.md

Lines changed: 0 additions & 227 deletions
This file was deleted.

docs/ProgrammingBlog/Cyan/general.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/ProgrammingBlog/Python/What_is_the_same/article.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

docs/blog/cpp/ret_based_overload.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# C++黑魔法之基于返回值的函数重载
2+
3+
!!! tip "阅读建议"
4+
阅读难度:中
5+
6+
!!! note "本文所有代码运行结果均在Windows 11 & g++ 11.2.0环境下通过实际编译运行进行了验证"
7+
8+
## 函数重载
9+
我们都知道,C++中的函数重载是很重要的特性之一,编译器会根据函数的参数列表来判断调用的函数。如:
10+
```cpp
11+
#include <iostream>
12+
13+
void f() {
14+
std::cout << "f()" << std::endl;
15+
}
16+
17+
void f(int) {
18+
std::cout << "f(int)" << std::endl;
19+
}
20+
21+
int main() {
22+
f();
23+
f(1);
24+
25+
return 0;
26+
}
27+
```
28+
输出:
29+
```output
30+
f()
31+
f(int)
32+
```
33+
34+
但是,函数重载只能根据参数列表来区分所调用的函数,而不能根据返回值来区分所调用的函数,即使接受返回值的变量提供了相关的类型信息。如:
35+
```cpp
36+
#include <iostream>
37+
38+
void f() {
39+
std::cout << "void f()" << std::endl;
40+
}
41+
42+
int f() {
43+
std::cout << "int f()" << std::endl;
44+
return 0;
45+
}
46+
47+
int main() {
48+
f();
49+
int ret = f();
50+
51+
return 0;
52+
}
53+
```
54+
编译以上代码会报错:
55+
```output
56+
source.cpp:7:5: error: ambiguating new declaration of 'int f()'
57+
7 | int f() {
58+
| ^
59+
source.cpp:3:6: note: old declaration 'void f()'
60+
3 | void f() {
61+
| ^
62+
source.cpp: In function 'int main()':
63+
source.cpp:14:16: error: void value not ignored as it ought to be
64+
14 | int ret = f();
65+
| ~^~
66+
```
67+
68+
## 基于返回值的函数重载
69+
尽管C++不支持基于返回值的函数重载,但是我们可以通过一些黑魔法来**模拟**实现这个功能(众所周知C++的黑魔法是格外的多)。说是黑魔法,其实只是利用了重载类型转换方法的技巧。先来看代码:
70+
```cpp
71+
#include <iostream>
72+
#include <string>
73+
74+
class Bool {
75+
public:
76+
Bool(bool value) : __value(value) {}
77+
78+
class _RetT {
79+
public:
80+
_RetT(const Bool& obj) : __bool_obj(obj) {}
81+
82+
operator bool() const {
83+
printf("bool-return overload\n");
84+
return this->__bool_obj.__value;
85+
}
86+
87+
operator std::string() const {
88+
printf("string-return overload\n");
89+
return this->__bool_obj.__value ? "true" : "false";
90+
}
91+
92+
private:
93+
const Bool& __bool_obj;
94+
};
95+
96+
[[nodiscard]]
97+
_RetT get_value() const {
98+
return *this;
99+
}
100+
101+
private:
102+
bool __value;
103+
};
104+
105+
int main() {
106+
auto bool_obj = Bool(true);
107+
bool b_ret = bool_obj.get_value();
108+
std::string str_ret = bool_obj.get_value();
109+
auto auto_ret = bool_obj.get_value();
110+
}
111+
```
112+
输出:
113+
```output
114+
bool-return overload
115+
string-return overload
116+
```
117+
上面的代码应该不是很难读。`Bool::get_value()`返回值的类型是一个内部定义的类型`_RetT`,而这个类型的对象持有`Bool`对象的引用,并且可以隐式转换为`bool`类型和`std::string`的对象。那么在`Bool::get_value()`返回的对象被不同类型的变量接收时,就会根据接收变量类型的不同来调用不同的类型转换函数,而在不同的类型转换函数中,可以模拟对于不同返回值的函数重载。
118+
119+
当用标记为`auto`的变量去接收这个返回值时,`auto`会被推导为`Bool::_RetT`,并且不会调用任何类型转换函数。如果忽略返回值,也是同样的效果。

0 commit comments

Comments
 (0)