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 的一个新特性,使我们可以实现一个 接近
函数返回值重载的功能。即 [自定义转换函数][https://en.cppreference.com/w/cpp/language/cast_operator] 。来看下面的例子:
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
的用户都可以根据需求实现或扩展这个类