函数重载(Function Overloading)允许在同一个作用域内定义多个功能类似但参数不同的函数。这些函数可以有相同的名字,但必须有不同的参数列表(参数的数量、类型或顺序不同)。编译器通过参数列表来决定调用哪个函数。
大部分语言并不支持返回值类型的重载。包括C++。
1 2 3 4 5 6 7 8 9 10 11 12 13 std::string to_string (int i) ;std::string to_string (bool b) ;std::string si = to_string (42 ); std::string sb = to_string (true ); 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; operator int () const ; operator bool () const ; }; int i = to_string_t {"42" }; bool b = to_string_t {"true" };
需要注意,编译器需要知道转换的目标类型。如 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" ); bool b = from_string ("true" );
任何使用 from_string
的用户都可以根据需求实现或扩展这个类