C++ 标准允许自定义类型的 std::to_string 特化吗?
Is specialization of std::to_string for custom types allowed by the C++ standard?
在 C++11 及更高版本中,是否允许在自定义类型的 std
命名空间中特化 std::to_string
?
namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}
示例用例:
int main() {
MyClass c;
std::cout << std::to_string(c) << std::endl;
}
如果我没记错的话,您可以简单地为泛型类型重载 to_string
:
template<typename T> to_string(const T& _x) {
return _x.toString();
}
这允许您的程序使用 ADL(参数相关查找)根据传递的类型正确选择相关的 to_string
方法。
In C++11 and later, is it allowed to specialize std::to_string in the std namespace for custom types?
没有。首先,it is not a template function 所以你根本无法特化它。
如果您询问有关添加自己的重载函数的问题,答案仍然相同。
来自 Extending the namespace std 的文档片段:
It is undefined behavior to add declarations or definitions to namespace std or to any namespace nested within std, with a few exceptions noted below
It is allowed to add template specializations for any standard library template to the namespace std only if the declaration depends on a user-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.
在实践中,一切都可能会正常工作,但严格来说,标准表示无法保证会发生什么。
编辑:我无法访问官方标准,因此以下内容来自 free working draft (N4296):
17.6.4.2 Namespace use
17.6.4.2.1 Namespace std
- The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a
namespace within namespace std unless otherwise specified. A program may add a template specialization
for any standard library template to namespace std only if the declaration depends on a user-defined type
and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.181
The behavior of a C++ program is undefined if it declares
2.1 — an explicit specialization of any member function of a standard library class template, or
2.2 — an explicit specialization of any member function template of a standard library class or class template,
or
2.3 — an explicit or partial specialization of any member class template of a standard library class or class
template.
A program may explicitly instantiate a template defined in the standard library only if the declaration
depends on the name of a user-defined type and the instantiation meets the standard library requirements
for the original template.
- A translation unit shall not declare namespace std to be an inline namespace (7.3.1).
更好的方法是创建自己的函数,如果可能的话使用 std::to_string
以及 .toString()
方法,只要它可用于传递的参数:
#include <type_traits>
#include <iostream>
#include <string>
struct MyClass {
std::string toString() const { return "MyClass"; }
};
template<class T>
typename std::enable_if<std::is_same<decltype(std::declval<const T&>().toString()), std::string>::value, std::string>::type my_to_string(const T &t) {
return t.toString();
}
template<class T>
typename std::enable_if<std::is_same<decltype(std::to_string(std::declval<T&>())), std::string>::value, std::string>::type my_to_string(const T &t) {
return std::to_string(t);
}
int main() {
std::cout << my_to_string(MyClass()) << std::endl; // will invoke .toString
std::cout << my_to_string(1) << std::endl; //will invoke std::to_string
}
In C++11 and later, is it allowed to specialize std::to_string in the std namespace for custom types?
不,您不能将重载添加到 to_string()
的 std
命名空间中。
好消息是 您不需要,有一个简单的解决方案!
您可以提供自己的实现,让ADL(argument dependent lookup)为您解决问题。
方法如下:
class A {};
std::string to_string(const A&)
{
return "A()";
}
int main()
{
A a;
using std::to_string;
std::cout << to_string(2) << ' ' << to_string(a);
}
这里我们使用了using declaration将std::to_string
带入作用域,然后我们使用了对to_string()
.
的非限定调用
现在 std::to_string
和 ::to_string
都可见,编译器会选择适当的重载。
如果你不想在每次使用 to_string
之前写 using std::to_string
或者你担心你会忘记在没有命名空间的情况下使用 to_string
你可以创建一个辅助函数
template<typename T>
std::string my_to_string(T&& t)
{
using std::to_string;
return to_string(std::forward<T>(t));
}
请注意,此函数可以在任何名称空间中定义,并且独立于定义 类 的名称空间工作(它们不必相同)。
参见example。
注意:如果您是调用 to_string
的人,此方法有效。如果有一个调用 std::to_string
的库,而你想为你的类型更改它,那你就不走运了。
在 C++11 及更高版本中,是否允许在自定义类型的 std
命名空间中特化 std::to_string
?
namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}
示例用例:
int main() {
MyClass c;
std::cout << std::to_string(c) << std::endl;
}
如果我没记错的话,您可以简单地为泛型类型重载 to_string
:
template<typename T> to_string(const T& _x) {
return _x.toString();
}
这允许您的程序使用 ADL(参数相关查找)根据传递的类型正确选择相关的 to_string
方法。
In C++11 and later, is it allowed to specialize std::to_string in the std namespace for custom types?
没有。首先,it is not a template function 所以你根本无法特化它。
如果您询问有关添加自己的重载函数的问题,答案仍然相同。
来自 Extending the namespace std 的文档片段:
It is undefined behavior to add declarations or definitions to namespace std or to any namespace nested within std, with a few exceptions noted below
It is allowed to add template specializations for any standard library template to the namespace std only if the declaration depends on a user-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.
在实践中,一切都可能会正常工作,但严格来说,标准表示无法保证会发生什么。
编辑:我无法访问官方标准,因此以下内容来自 free working draft (N4296):
17.6.4.2 Namespace use
17.6.4.2.1 Namespace std
- The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.181
The behavior of a C++ program is undefined if it declares
2.1 — an explicit specialization of any member function of a standard library class template, or
2.2 — an explicit specialization of any member function template of a standard library class or class template, or
2.3 — an explicit or partial specialization of any member class template of a standard library class or class template.
A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
- A translation unit shall not declare namespace std to be an inline namespace (7.3.1).
更好的方法是创建自己的函数,如果可能的话使用 std::to_string
以及 .toString()
方法,只要它可用于传递的参数:
#include <type_traits>
#include <iostream>
#include <string>
struct MyClass {
std::string toString() const { return "MyClass"; }
};
template<class T>
typename std::enable_if<std::is_same<decltype(std::declval<const T&>().toString()), std::string>::value, std::string>::type my_to_string(const T &t) {
return t.toString();
}
template<class T>
typename std::enable_if<std::is_same<decltype(std::to_string(std::declval<T&>())), std::string>::value, std::string>::type my_to_string(const T &t) {
return std::to_string(t);
}
int main() {
std::cout << my_to_string(MyClass()) << std::endl; // will invoke .toString
std::cout << my_to_string(1) << std::endl; //will invoke std::to_string
}
In C++11 and later, is it allowed to specialize std::to_string in the std namespace for custom types?
不,您不能将重载添加到 to_string()
的 std
命名空间中。
好消息是 您不需要,有一个简单的解决方案!
您可以提供自己的实现,让ADL(argument dependent lookup)为您解决问题。
方法如下:
class A {};
std::string to_string(const A&)
{
return "A()";
}
int main()
{
A a;
using std::to_string;
std::cout << to_string(2) << ' ' << to_string(a);
}
这里我们使用了using declaration将std::to_string
带入作用域,然后我们使用了对to_string()
.
现在 std::to_string
和 ::to_string
都可见,编译器会选择适当的重载。
如果你不想在每次使用 to_string
之前写 using std::to_string
或者你担心你会忘记在没有命名空间的情况下使用 to_string
你可以创建一个辅助函数
template<typename T>
std::string my_to_string(T&& t)
{
using std::to_string;
return to_string(std::forward<T>(t));
}
请注意,此函数可以在任何名称空间中定义,并且独立于定义 类 的名称空间工作(它们不必相同)。
参见example。
注意:如果您是调用 to_string
的人,此方法有效。如果有一个调用 std::to_string
的库,而你想为你的类型更改它,那你就不走运了。