jot*_*tik 36 c++ std tostring specialization c++11
在C++ 11及更高版本中,是否允许专用std::to_string
于std
自定义类型的命名空间?
namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}
Run Code Online (Sandbox Code Playgroud)
示例用例:
int main() {
MyClass c;
std::cout << std::to_string(c) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
Jam*_*son 33
在C++ 11及更高版本中,是否允许在std命名空间中为自定义类型专门化std :: to_string?
不.首先,它不是模板功能,所以你根本不能专门化它.
如果您要求添加自己的过载功能,答案仍然保持不变.
来自扩展命名空间std的文档片段:
将声明或定义添加到命名空间std或嵌套在std中的任何命名空间是未定义的行为,下面列出了一些例外情况
只有当声明取决于用户定义的类型且专业化满足原始模板的所有要求时,才允许将任何标准库模板的模板特化添加到命名空间std,除非禁止此类特殊化.
在实践中,一切都可能正常工作,但严格来说,标准说不能保证会发生什么.
编辑:我无法访问官方标准,因此以下内容来自免费工作草案(N4296):
17.6.4.2命名空间使用
17.6.4.2.1命名空间std
- 如果C++程序向命名空间std或命名空间std中的命名空间添加声明或定义,则它是未定义的,除非另有说明.只有当声明取决于用户定义的类型并且特化符合原始模板的标准库要求且未明确禁止时,程序才可以将任何标准库模板的模板特化添加到命名空间std.181
如果声明,C++程序的行为是不确定的
2.1 - 标准库类模板的任何成员函数的显式特化,或
2.2 - 标准库类或类模板的任何成员函数模板的显式特化,或
2.3 - 标准库类或类模板的任何成员类模板的显式或部分特化.
仅当声明取决于用户定义类型的名称并且实例化符合原始模板的标准库要求时,程序才可以显式实例化标准库中定义的模板.
- 转换单元不应将namespace std声明为内联命名空间(7.3.1).
sjr*_*son 11
如果我没弄错,你可以简单地重载to_string
泛型:
template<typename T> to_string(const T& _x) {
return _x.toString();
}
Run Code Online (Sandbox Code Playgroud)
这允许程序使用ADL(参数依赖查找)来to_string
根据传递的类型正确选择相关方法.
更好的方法是创建自己的函数,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
}
Run Code Online (Sandbox Code Playgroud)
在 C++11 及更高版本中,是否允许在 std 命名空间中为自定义类型专门化 std::to_string?
不,你不能添加过载到std
命名空间to_string()
。
好消息是您不需要这样做,有一个简单的解决方案!
您可以提供自己的实现,让 ADL(参数相关查找)为您解决问题。
就是这样:
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);
}
Run Code Online (Sandbox Code Playgroud)
这里我们使用了using 声明来引入std::to_string
作用域,然后我们使用了对 的非限定调用to_string()
。
现在,std::to_string
和::to_string
都是可见的,编译器会选择适当的重载。
如果你不想using std::to_string
在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));
}
Run Code Online (Sandbox Code Playgroud)
请注意,此函数可以在任何命名空间中定义,并且与定义类的命名空间无关(它们不必相同)。
请参阅示例。
注意:如果您是来电者,此方法有效to_string
。如果有一个库调用std::to_string
并且您想为您的类型更改它,那么您就不走运了。
归档时间: |
|
查看次数: |
4630 次 |
最近记录: |