为什么 std::to_string() 没有模板化?
Why is std::to_string() not templated?
如前所述 std::string
不是模板函数,而是标准选择使用函数重载为不同类型提供此函数。我的问题是为什么在这种情况下 template/specialisation 对我来说似乎更有意义时使用重载?考虑一下,如果标准定义了这样的东西:
template <typename T>
std::string std::to_string(const T& v);
然后我们可以在我们的程序中自由地为任何类型添加特殊化以符合这个签名,这样 C++ 将有一个统一的方法将类型转换为人类可读的字符串。为什么不这样做呢?当前设计背后的想法是什么?
编辑 1:
我对当前设计的主要批评是,不允许向 std
添加重载,因此我们不能编写类似 std:to_string(object-that-is-of-user-defined-types)
的任何内容,并且不得不退而求其次定义 to_string()
在他们自己的命名空间中并记住在哪里使用他们的版本或 std
版本取决于他们正在处理的类型......这听起来让我头疼。
我真正喜欢 Python(或其他一些语言)的一件事是,您可以通过实施一些魔术方法使您自己的类型像本机类型一样工作。我认为这个问题的根本原因是为什么 C++ 决定禁止人们为他们自己的类型实现 std::to_string()
,从而禁止我们在任何地方都遵循相同的接口。
对于像 hash
或 to_string()
这样的常见事物,在语言/stdlib
级别上使用单一界面然后期望用户遵守该界面不是更好吗,而不是拥有多个接口?
why C++ decided to disallow people to implement std::to_string
for their own type
这就是 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
具有可以接受 T const &
参数的 to_string
函数,这同样有效。例如:
namespace example {
class Foo;
std::string to_string(Foo const &);
}
to_string_example(example::Foo{})
会找到并使用相应的 example::to_string
函数。
remember where to use their version or the std version depends on the types they are dealing with... This sounds like a headache for me.
如果这真的让您头疼,您可以在项目中将 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(...)
而不必考虑它。
这听起来可能有点无聊,但是 std::to_string
的目的是像您使用 sprintf
一样格式化并且 sprintf
仅支持有限的类型集,这是std::to_string
也是如此。无需将其设为模板。
正如 中详细解释的那样,设计没有您认为的限制。您仍然可以提供自己的 foo::to_string(foo::bar&)
并且在使用适当的名称限定来启用 ADL 的代码中将调用您的重载。为此,没有必要向 std
.
添加重载
如前所述 std::string
不是模板函数,而是标准选择使用函数重载为不同类型提供此函数。我的问题是为什么在这种情况下 template/specialisation 对我来说似乎更有意义时使用重载?考虑一下,如果标准定义了这样的东西:
template <typename T>
std::string std::to_string(const T& v);
然后我们可以在我们的程序中自由地为任何类型添加特殊化以符合这个签名,这样 C++ 将有一个统一的方法将类型转换为人类可读的字符串。为什么不这样做呢?当前设计背后的想法是什么?
编辑 1:
我对当前设计的主要批评是,不允许向 std
添加重载,因此我们不能编写类似 std:to_string(object-that-is-of-user-defined-types)
的任何内容,并且不得不退而求其次定义 to_string()
在他们自己的命名空间中并记住在哪里使用他们的版本或 std
版本取决于他们正在处理的类型......这听起来让我头疼。
我真正喜欢 Python(或其他一些语言)的一件事是,您可以通过实施一些魔术方法使您自己的类型像本机类型一样工作。我认为这个问题的根本原因是为什么 C++ 决定禁止人们为他们自己的类型实现 std::to_string()
,从而禁止我们在任何地方都遵循相同的接口。
对于像 hash
或 to_string()
这样的常见事物,在语言/stdlib
级别上使用单一界面然后期望用户遵守该界面不是更好吗,而不是拥有多个接口?
why C++ decided to disallow people to implement
std::to_string
for their own type
这就是 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
具有可以接受 T const &
参数的 to_string
函数,这同样有效。例如:
namespace example {
class Foo;
std::string to_string(Foo const &);
}
to_string_example(example::Foo{})
会找到并使用相应的 example::to_string
函数。
remember where to use their version or the std version depends on the types they are dealing with... This sounds like a headache for me.
如果这真的让您头疼,您可以在项目中将 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(...)
而不必考虑它。
这听起来可能有点无聊,但是 std::to_string
的目的是像您使用 sprintf
一样格式化并且 sprintf
仅支持有限的类型集,这是std::to_string
也是如此。无需将其设为模板。
正如 foo::to_string(foo::bar&)
并且在使用适当的名称限定来启用 ADL 的代码中将调用您的重载。为此,没有必要向 std
.