27 votes

Cas d'utilisation de std::add_const et similaires

Certaines transformations de type dans <type_traits> peut également être exprimée à l'aide de la syntaxe du langage de base (par ex. std::add_const<T>::type est/semble équivalent à const T ). Dtto pour std::add_lvalue_reference et peut-être d'autres. Quelle est l'utilité de ce type de traits ?

Je comprends parfaitement que la norme fournirait une "boîte à outils incomplète" sans eux, et je peux imaginer une utilisation de type méta, quelque chose comme ceci :

template<typename In, template <typename> class Modifier>
struct Apply {
  typedef typename Modifier<T>::type Out;
};

Apply<int, std::add_const>

Existe-t-il d'autres cas d'utilisation de ces traits qui peuvent être exprimés de manière syntaxique, ou sont-ils simplement inclus "par souci d'exhaustivité" et pour une méta-utilisation occasionnelle ?

23voto

Jonathan Wakely Points 45593

Ces traits proviennent de Boost et de la proposition de les ajouter à la norme, N1345 , cite les propos d'Andrei Alexandrescu :

"Je comprends l'argument de la symétrie pour ajouter add_const , add_volatile , add_cv y add_pointer Cependant, je plaiderais en faveur de leur élimination. Les équivalents fournis par le langage sont tout simplement plus simples et plus agréables."

La même proposition donne également ce raisonnement :

Note de l'auteur : superficiellement, les classes add_const, add_volatile et add_cv ne sont pas pertinentes, puisque, par exemple, add_const::type est identique à T const, pour tous les T (actuellement, cela ne s'applique pas aux types de fonction - mais numéro 295 aborde cette question). Cependant, l'expérience de Boost est que plusieurs utilisateurs ont demandé que ces modèles soient présents dans la bibliothèque pour les raisons suivantes : (a) Certains utilisateurs les trouvent plus explicites - lorsqu'ils combinent des modèles de transformation en particulier, les utilisateurs apprécient le type de "documentation intégrée" que ces modèles fournissent. (b) Tous les utilisateurs ne savent pas que la cv-qualification d'une référence est autorisée et n'a aucun effet, ou que la cv-qualification d'un type qui est déjà cv-qualifié est autorisée et n'a aucun effet. (c) Les compilateurs peuvent émettre des avertissements lors de la qualification en cv d'un type qui est une référence, ou qui a déjà un qualificateur en cv, ces modèles peuvent être implémentés de telle sorte que ces messages soient supprimés dans ces cas.

De même, pour add_reference (renommé en add_lvalue_reference dans la norme) :

Note de l'auteur : le modèle add_reference était l'une des motivations initiales de la bibliothèque de traits de type boost. Cependant, la résolution de numéro 106 fait que le modèle semble largement redondant. Malgré cela, add_reference peut s'avérer utile pour supprimer les avertissements du compilateur lors de la création par inadvertance de références à des références dans le code du modèle.

8voto

Jan Herrmann Points 1643

Ces traits sont fournis pour une méta-utilisation occasionnelle. Ils permettent de transporter les cv-qualificateurs souhaités dans la métaprogrammation.

template<class T,template<class> class Trait>
struct transform
{
  /* working with T creating newT*/

  typedef Trait<newT>::type type;
};

template<class T>
struct special_transform
  : transfrom<T, std::add_const>
{};

Dans ce cas, vous ne pourriez pas remplacer std::add_const con const .

7voto

Joseph Thomson Points 335

add_const peut être utilisé pour résoudre les conflits de déduction de type.

template <typename T>
class wrapper;

template <typename T>
bool operator==(wrapper<T> const& w, T const& t);

Les problèmes surviennent si nous utilisons wrapper<T const> :

wrapper<int const> w = { 42 };
assert(w == 42); // Error: conflicting deduced types

T est simultanément déduit comme étant à la fois int et int const . Ce problème peut être résolu en utilisant add_const :

template <typename T>
bool operator==(wrapper<T> const& w, add_const_t<T>& t);

1voto

Orient Points 736

Le seul cas d'utilisation que je connaisse est illustré ci-dessous :

struct F
{
    bool f() const { return true; }
    bool f() { return false; }
};
assert(!F{}.f())
assert(std::add_const_t< F >{}.f());

Il est également nécessaire de tester qualifié cv-ref la fonctionnalité des fonctions membres, qui peut différer selon les surcharges (uniquement pour les C++ modernes qualifiés lref). std::as_const fonction) :

struct F
{
    int g() & { return 1; }
    int g() const & { return 2; }
    int g() && { return 3; }
    int g() const && { return 4; }
};
F f;
assert(f.g() == 1);
assert(std::as_const(f).g() == 2);
assert(F{}.g() == 3);
assert(std::add_const_t< F >{}.g() == 4); // rarely needed, but if needed, then it helps

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