2 votes

Autodocumenter un alias de type (typedef) pour indiquer qu'il sera utilisé dans une autre classe donnée

Comment auto-documenter un type-alias qui est utilisé dans une autre bibliothèque ?

Dans l'exemple ci-dessous, la classe User définit un alias User::type qui n'est censé être mentionné que dans la classe Library via T::type .

Voici le schéma :-

enter image description here

Library.h

Library<T> attendu seulement T qui définit un certain alias (par ex. T::type dans cet exemple).

#include <iostream>
class Base{};     //dummy for the sake of example
template<class T>class Library{
    Base* t=nullptr;
    public: typename T::type getValue(){return static_cast<typename T::type>(t);}
    //some complex function, e.g. T::aType::doSomething()
};

Dans des cas concrets, Library<T> attendue nombreux alias, par exemple T::aType , T::bType , T::callbackType , etc.

User.h

Pour utiliser la bibliothèque ci-dessus, ::type doit être défini, par exemple, comme suit :-

class Derived : public Base{};  //dummy for the sake of example
class User{
    public: using type=Derived*;//<-- poorly documented
    //... other alias e.g. aType=int*, bType=SomeClass*
    //... other complex functions
};

Voici l'utilisation ( Démonstration complète ):-

int main(){
     Library<User> lib;
     lib.getValue();
     std::cout<<"OK"<<std::endl;
}

Problème

Notez que User::type manque vraiment d'auto-documentation.
Dans la vie réelle, la plupart des codeurs - y compris ceux qui l'ont conçu - oublient ce qu'est le User::type est destiné à.

User::type n'est pas référencée en interne dans User.h Il s'agit donc d'une cible facile à supprimer au hasard par certains codeurs.

Je sens que nos codes bien-aimés sont pourris de l'intérieur, et je réfléchis aux moyens de les sauver.

Question

Comment auto-documenter l'alias de type pour indiquer comment/où il se trouve ? appelé ?

Mes mauvaises solutions

1. commentaire

 class User{
    /** It is used for Library.h */
    public: using type=Derived*;

Il se salit assez vite, et je préfère encore utiliser la sémantique C++ plutôt que le commentaire aléatoire.

2. rendre le nom du type plus descriptif

 class User{
    /** It is used for Library.h */
    public: using LIBRARY_type=Derived*;

C'est assez désordonné.

Remarque : Cette question est similaire à Comment auto-documenter une fonction callback appelée par une classe de la bibliothèque template ? mais celui-ci est consacré à type-def alors que celle-ci porte sur callback .

2voto

Il semble que votre seul problème réel soit que "c'est une cible facile qui peut être supprimée au hasard par certains codeurs".

La solution n'est pas d'être obsédé par l'auto-documentation et les noms, mais d'instituer des examen par les pairs y tests de régression . Pourquoi les codeurs de votre équipe suppriment-ils des choses au hasard et s'en sortent-ils ? Il faut que cela cesse.

Vous pouvez probablement vous épargner le casse-tête administratif d'avoir à revenir sur une telle modification, avec un simple commentaire de code :

/**
 * Provided for use by Library.
 */
using type=Derived*;

C'est tout. C'est tout ce dont vous avez besoin. Ce n'est pas du tout "sale" - cela indique aux autres codeurs pourquoi l'article en question a été modifié. type déclaration existe, et se distinguera comme un pouce douloureux en diff si quelqu'un l'enlève. Vous pourrez alors leur demander : "Comment avez-vous conclu que Library n'a plus besoin de cette déclaration, et pourquoi le fait de la supprimer vaut-il la rupture de notre API ?"

En bref, il s'agit uniquement d'un problème humain. Il existe de nombreux exemples dans la bibliothèque standard de types membres appelés type D'un point de vue technique, vous faites donc déjà ce qu'il faut. N'essayez pas d'insérer des noms qui reflètent les caractéristiques attendues de votre type. utilisation ; faire en sorte que le nom décrive ce qu'il es . Le comité C++ a commis la même erreur avec std::move !

1voto

Jarod42 Points 15729

Vous pouvez créer un type de traits pour cela :

template <typename T> struct library_trait; // No definition
// Need to define library_trait<T>::type for ...
// library_trait<T>::atype for ...

En classe Library , utiliser library_trait<T>::type au lieu de typename T::Type

Dans un lieu avant l'utilisation de Library<User> (comme dans main dans votre exemple) :

Se spécialiser library_trait pour User .

template <> struct library_trait<User>
{
    using type = Derived*;
    // ...
};

1voto

Yakk Points 31636

Une classe de traits est la solution habituelle à ce problème. Elle est gênante parce qu'il faut la spécialiser dans son propre espace de noms.

Une autre solution consiste à créer une fonction de trait.

namespace utility {
  template<class T>struct tag_t{using type=T; constexpr tag_t(){}};
  template<class T>constexpr tag_t<T> tag{};
  template<class Tag> using type_t=typename Tag::type;
}
namespace MyLibrary {
  template<class T>
  void library_trait_name_f(tag_t<T>,...);
  template<class T>using library_trait_name=type_t<decltype(library_trait_name_f(tag<T>))>;
}

maintenant supposer que vous l'avez fait :

namespace Elsewhere {
  struct Foo;
}

vous pouvez écrire n'importe où :

namespace Elsewhere { // or MyLibrary, or even utility
  tag_t<int> library_trait_name_f(tag_t<Foo>);
}

et s'il est visible, il sera récupéré par MyLibrary::library_trait_name<T> . En particulier, MyLibrary::library_trait_name<Elsewhere::Foo> es int .

L'avantage de cette méthode est qu'elle vous permet d'écrire la liaison entre la bibliothèque et le type dans la bibliothèque, à côté du type ou à un troisième endroit. Le principal inconvénient est l'absence de cadrage et le caractère non conventionnel de cette méthode.

MSVC ne se comporte pas bien non plus avec les SFINAE basées sur le decltype, donc l'utilisation de ce qui précède pour les SFINAE dans MSVC doit se faire avec précaution.

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