如上所述,here std::string
不是模板函数,而是标准选择使用函数重载为不同类型提供此函数。我的问题是为什么在这种情况下,当模板/专业化对我来说更有意义时,为什么要使用重载?考虑一下,如果该标准定义了以下内容:
template <typename T>
std::string std::to_string(const T& v);
然后,我们可以为程序中的任何类型自由添加特殊化以符合此签名,因此C ++将具有一种统一的方式将类型转换为人类可读的字符串。为什么不这样做呢?当前设计背后的想法是什么?
编辑1:
我对当前设计的主要批评是不允许在std
上添加重载,因此我们不能编写类似std:to_string(object-that-is-of-user-defined-types)
的内容,而不得不依靠定义{{1} }放在自己的命名空间中,并记住在何处使用其版本或to_string()
版本取决于他们正在处理的类型...这听起来让我感到头疼。
我真的很喜欢Python(或其他一些语言)的一件事是,您可以通过实现一些魔术方法使自己的类型像本机类型一样工作。我认为这个问题的根本原因在于,为什么C ++决定禁止人们为其自己的类型实现std
,从而禁止我们在任何地方都遵循相同的接口。
对于诸如std::to_string()
或hash
这样的常见事物,在语言/ to_string()
级别上具有单个界面然后期望用户遵循该界面不是更好,而不是有多个接口?
答案 0 :(得分:5)
为什么C ++决定禁止人们为自己的类型实现
std::to_string
这是ADL有用的地方。我们已经有了使用std::swap
正确执行此操作的示例,该示例已在许多代码库中成功完成:
template <typename T>
void swap_example(T & a, T & b) {
using std::swap;
swap(a, b);
}
如果在其中声明了命名空间T
具有兼容的swap()
函数,而无需要重载std::swap
,则此方法有效。我们可以使用std::to_string
做同样的事情:
template <typename T>
void to_string_example(T const & x) {
using std::to_string;
to_string(x);
}
如果声明的命名空间T
具有可以接受to_string
参数的T const &
函数,这同样可以工作。例如:
namespace example {
class Foo;
std::string to_string(Foo const &);
}
to_string_example(example::Foo{})
将找到并使用相应的example::to_string
函数。
记住在哪里使用他们的版本或std版本取决于他们正在处理的类型...这听起来让我很头疼。
如果这确实让您头疼,您可以将ADL隐藏在项目中的实用程序功能后面:
template <typename T>
std::string adl_to_string(T const & x) {
using std::to_string;
return to_string(x);
}
现在,您可以在各处使用adl_to_string(...)
而不是std::to_string(...)
,而不必考虑它。
答案 1 :(得分:2)
这听起来可能有点无聊,但是export class CustomerEditComponent implements OnInit {
constructor() {}
options: CityMaster[];
selectedOption: string;
ngOnInit(): void {
this.options = [
{ id: 1, cityName: "Mumbai" },
{ id: 2, cityName: "Delhi" },
{ id: 3, cityName: "Banglore" },
{ id: 4, cityName: "Lucknow" }
];
}
}
的目的是像您曾经使用过std::to_string
一样进行格式化,并且由于sprintf
仅支持一组有限的类型,所以这也是正确的sprintf
。无需使其成为模板。
正如this answer中详细解释的那样,设计没有您认为有的限制。您仍然可以提供自己的std::to_string
,并且在使用正确的名称限定来启用ADL的代码中,将调用您的重载。为此,没有必要向foo::to_string(foo::bar&)
添加重载。