42 votes

La spécialisation de std :: to_string pour les types personnalisés est-elle autorisée par la norme C ++?

En C ++ 11 et versions ultérieures, est-il autorisé à spécialiser std::to_string dans l'espace de noms std pour les types personnalisés?

 namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}
 

Exemple de cas d'utilisation:

 int main() {
    MyClass c;
    std::cout << std::to_string(c) << std::endl;
}
 

36voto

James Adkison Points 6334

En C++11 et, plus tard, est-il permis de se spécialiser std::to_string dans l'espace de noms std pour les types personnalisés?

Pas de. Tout d'abord, il n'est pas un modèle de fonction de sorte que vous ne pouvez pas se spécialisent à tous.

Si vous vous posez sur l'ajout de votre propre la surcharge de fonctions, la réponse reste toujours la même.

Extrait de la Documentation de l'Extension de l'espace de noms std:

C'est un comportement indéfini d'ajouter des déclarations ou des définitions de l'espace de noms std ou pour tout espace imbriqué dans le std, avec quelques exceptions notées ci-dessous

Il est permis d'ajouter des spécialisations de modèle pour toute la bibliothèque standard du modèle de l'espace de noms std seulement si la déclaration dépend d'un type défini par l'utilisateur et de la spécialisation satisfait à toutes les exigences pour le modèle d'origine, sauf lorsque ces spécialisations sont interdits.


Dans la pratique, tout sera probablement très bien, mais, à strictement parler, la norme dit qu'il n'ya aucune garantie de ce qui va arriver.


Edit: je n'ai pas accès à la norme officielle donc la suite est de la libre projet de travail (N4296):

17.6.4.2 utilisation de l'espace de Noms

17.6.4.2.1 Namespace std

  1. Le comportement d'un programme C++ n'est pas définie si on ajoute les déclarations ou les définitions de l'espace de noms std ou à un espace de noms au sein de l'espace de noms std, sauf indication contraire. Un programme peut ajouter un modèle de spécialisation pour toute bibliothèque standard template namespace std seulement si la déclaration dépend d'un type défini par l'utilisateur et de la spécialisation répond à la norme de la bibliothèque exigences pour le modèle d'origine et n'est pas explicitement l'interdit.181
  2. Le comportement d'un programme C++ n'est pas définie si elle déclare

    2.1 - une spécialisation explicite de toute fonction membre d'une bibliothèque standard modèle de classe, ou

    2.2 - une spécialisation explicite de toute fonction membre template d'une bibliothèque standard de la classe ou de la classe de modèle, ou

    2.3 - explicite ou partielle de la spécialisation d'un membre de la classe du modèle de la bibliothèque standard de la classe ou de la classe de modèle.

    Un programme peut instancier explicitement un modèle défini dans la bibliothèque standard uniquement si la déclaration dépend du nom d'un type défini par l'utilisateur et l'instanciation répond aux exigences de la bibliothèque standard pour le modèle d'origine.

  3. Une unité de traduction ne doivent pas déclarer l'espace de noms std être une ligne de l'espace de noms (7.3.1).

14voto

Si je ne me trompe pas, vous pouvez simplement surcharger to_string pour un type générique:

 template<typename T> to_string(const T& _x) {
    return _x.toString();
}
 

et cela permet à votre programme d'utiliser ADL (recherche dépendante de l'argument) pour choisir correctement la méthode to_string appropriée en fonction du type transmis.

9voto

W.F. Points 3008

Le meilleur moyen serait de créer votre propre fonction utilisant les méthodes std::to_string si possible, ainsi que la méthode .toString() chaque fois qu'elle est disponible pour les arguments passés:

 #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
}
 

7voto

Makers_F Points 988

En C++11 et, plus tard, est-il permis de se spécialiser std::to_string dans l'espace de noms std pour les types personnalisés?

Non, vous ne pouvez pas ajouter une surcharge dans l' std d'espace de noms pour to_string().

La bonne nouvelle est que vous n'avez pas besoin d', il existe une solution simple!

Vous pouvez fournir votre propre mise en œuvre et laissez-ADL (argument dépendante de recherche) résoudre le problème pour vous.

Voici comment:

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);
}

Ici nous avons utilisé l' aide de déclaration d'amener std::to_string dans le champ, et puis nous avons utilisé les non qualifiés appel à l' to_string().

Maintenant, les deux std::to_string et ::to_string sont visibles et le compilateur détermine la appropriée de surcharge.

Si vous ne voulez pas écrire using std::to_string avant d'utiliser to_string chaque fois ou vous avez peur, vous oubliez d'utiliser to_string sans l'espace de noms, vous pouvez créer une fonction d'assistance

template<typename T>
std::string my_to_string(T&& t)
{
    using std::to_string;
    return to_string(std::forward<T>(t));
}

Notez que cette fonction peut être défini dans un espace de noms et fonctionne indépendamment de l'espace de noms dans lequel les classes sont définies (ils n'ont pas à être les mêmes).

Voir l' exemple.

REMARQUE: ce fonctionne si vous êtes l'un appelant to_string. Si il y a une bibliothèque qui appelle std::to_string et que vous souhaitez modifier votre types que vous êtes hors de la chance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X