not - ¿Es la especialización de std:: to_string para los tipos personalizados permitidos por el estándar de C++?
to_string is not a member of std (4)
En C ++ 11 y posteriores, ¿se permite especializar std :: to_string en el espacio de nombres std para tipos personalizados?
No, no puede agregar una sobrecarga en el espacio de nombres to_string()
para to_string()
.
La buena noticia es que no es necesario, ¡hay una solución simple!
Puede proporcionar su propia implementación y dejar que ADL (búsqueda dependiente del argumento) resuelva el problema por usted.
Así es cómo:
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);
}
Aquí usamos la declaración using para traer std::to_string
al alcance, y luego usamos la llamada no calificada a to_string()
.
Ahora tanto std::to_string
como ::to_string
son visibles y el compilador selecciona la sobrecarga apropiada.
Si no desea escribir using std::to_string
antes de usar to_string
cada vez o si teme que se olvide de usar to_string
sin el espacio de nombres, puede crear una función de ayuda
template<typename T>
std::string my_to_string(T&& t)
{
using std::to_string;
return to_string(std::forward<T>(t));
}
Tenga en cuenta que esta función se puede definir en cualquier espacio de nombres y funciona independientemente del espacio de nombres en el que se definen las clases (no tienen que ser las mismas).
Mira el example .
NOTA : esto funciona si usted es el que está llamando a to_string
. Si hay una biblioteca que llama a std::to_string
y desea cambiarla para sus tipos, no tiene suerte.
En C ++ 11 y posteriores, ¿se permite especializar std::to_string
en el espacio de nombres std
para tipos personalizados?
namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}
Muestra de caso de uso:
int main() {
MyClass c;
std::cout << std::to_string(c) << std::endl;
}
En C ++ 11 y posteriores, ¿se permite especializar std :: to_string en el espacio de nombres std para tipos personalizados?
No. Antes que nada, no es una función de plantilla, así que no puedes especializarte en absoluto.
Si está preguntando acerca de agregar sus propias funciones de sobrecarga, la respuesta sigue siendo la misma.
Fragmento de documentación de Extender el espacio de nombres estándar :
Es un comportamiento indefinido agregar declaraciones o definiciones al espacio de nombres std o a cualquier espacio de nombres anidado dentro de std, con algunas excepciones que se detallan a continuación
Se permite agregar especializaciones de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombre std solo si la declaración depende de un tipo definido por el usuario y la especialización cumple todos los requisitos para la plantilla original, excepto cuando dichas especializaciones están prohibidas.
En la práctica todo probablemente funcionará bien, pero estrictamente hablando, el estándar dice que no hay garantía de lo que sucederá.
Editar: no tengo acceso al estándar oficial así que lo siguiente es del borrador de trabajo libre (N4296) :
17.6.4.2 Uso del espacio de nombres
17.6.4.2.1 Espacio de nombres estándar
- El comportamiento de un programa C ++ no está definido si agrega declaraciones o definiciones al espacio de nombres std o a un espacio de nombres dentro del espacio de nombres estándar, a menos que se especifique lo contrario. Un programa puede agregar una especialización de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombre std solo si la declaración depende de un tipo definido por el usuario y la especialización cumple con los requisitos de biblioteca estándar para la plantilla original y no está explícitamente prohibida. 181
El comportamiento de un programa C ++ no está definido si declara
2.1 - una especialización explícita de cualquier función miembro de una plantilla de clase de biblioteca estándar, o
2.2 - una especialización explícita de cualquier plantilla de función miembro de una clase de biblioteca estándar o plantilla de clase, o
2.3 - una especialización explícita o parcial de cualquier plantilla de clase miembro de una clase de biblioteca estándar o plantilla de clase.
Un programa puede instanciar explícitamente una plantilla definida en la biblioteca estándar solo si la declaración depende del nombre de un tipo definido por el usuario y la instanciación cumple con los requisitos de la biblioteca estándar para la plantilla original.
- Una unidad de traducción no declarará el espacio de nombre std como un espacio de nombre en línea (7.3.1).
Si no me equivoco, simplemente puede sobrecargar to_string
para un tipo genérico:
template<typename T> to_string(const T& _x) {
return _x.toString();
}
y esto permite el uso de ADL (búsqueda dependiente de argumentos) por su programa para elegir correctamente el método to_string
relevante en función del tipo pasado.
Una mejor forma sería crear su propia función que haga uso de std::to_string
si es posible así como del método .toString()
siempre que esté disponible para el argumento pasado:
#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
}