C++: 函数返回值可以重载吗

函数重载(Function Overloading)允许在同一个作用域内定义多个功能类似但参数不同的函数。这些函数可以有相同的名字,但必须有不同的参数列表(参数的数量、类型或顺序不同)。编译器通过参数列表来决定调用哪个函数。

大部分语言并不支持返回值类型的重载。包括C++。

1
2
3
4
5
6
7
8
9
10
11
12
13
// OK
std::string to_string(int i);
std::string to_string(bool b);

std::string si = to_string(42);
std::string sb = to_string(true);

// ERROR
int from_string(std::string_view s);
bool from_string(std::string_view s);

int i = from_string("42");
bool b = from_string("false");

C++ 11 的一个新特性,使我们可以实现一个 接近 函数返回值重载的功能。即 自定义转换函数
来看下面的例子:

1
2
3
4
5
6
7
8
9
10
struct to_string_t
{
std::string_view s; //string_view from c++17

operator int() const;
operator bool() const;
};

int i = to_string_t{"42"}; // operator int() const;
bool b = to_string_t{"true"}; // operator bool() const;

需要注意,编译器需要知道转换的目标类型。如 auto i = to_string_t{"42"} ,编译器不知道应该调用哪个重载。
让我们回到开始:如何将 to_string_t 作为返回值,似乎就可以完成 函数返回值重载 的功能:

1
2
3
4
5
6
7
8
9
10
11
12
to_string_t from_string(std::string_view str){
return to_string_t{str};
};

int i = from_string("42");
auto b = bool(from_string("42"));

void foo(int i, bool b){}
foo(from_string("42"), from_string("true"));

std::vector<int> v;
v.emplace_back(from_string("42"));

上面的代码中, 我们给出了 bool int 两种转换。如果想要它变得更灵活, 可以使用模板偏特化来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
template<typename T>
struct always_false : std::false_type {};

template<typename T>
struct to_string_impl{
static_assert(always_false<T>(), "No to_string_impl for this type");
};

struct to_string_t{
std::string_view s;

template<typename T>
operator T() const {
return to_string_impl<T>::from_string(s);
}
};

template<>
struct to_string_impl<int>{
static int from_string(std::string_view s){
return std::stoi(std::string(s));
}
};

to_string_t from_string(std::string_view s){return to_string_t{s};}

在实际使用中, 我们可以根据需求对 to_string_impl<T> 进行偏特化实现。对于未实现的类型则会在编译时抛出 Error.

1
2
int i = from_string("42");  //OK
bool b = from_string("true"); //ERROR error: static_assert failed due to requirement 'always_false<bool>()' "No to_string_impl for this type"

任何使用 from_string 的用户都可以根据需求实现或扩展这个类