web-dev-qa-db-fra.com

Approche C ++ moderne pour fournir des arguments facultatifs

Prenons la déclaration de fonction suivante:

void print(SomeType const* i);

Ici le const* nature de l'argument i suggère l'intention, que le paramètre est en option, car il peut être nullptr. Si cela n'était pas prévu, l'argument serait plutôt un const&. Communication Facultatif - La sémantique n'était certainement pas l'intention d'origine pour la conception des pointeurs, mais les utiliser pour le faire, il arrive de fonctionner très bien pendant une longue période.

Maintenant, étant donné que l'utilisation des pointeurs bruts est généralement découragé dans le C++ moderne (et doit être évité en faveur de std::unique_ptr et std::shared_ptr Pour indiquer précisément particulier Propriété - Sémantique), je me demande comment indiquer correctement les paramètres de fonction ' Facultatif - Sémantique Sans passer de la valeur , i. e. Copie , comme

void print(std::optional<SomeType> i);

ferait.

Après avoir pensé pendant un moment où j'ai eu l'idée d'utiliser:

void print(std::optional<SomeType const&> i);

Cela serait en fait plus précis. Mais il s'avère que std::optionalne peut pas avoir de types de référence . ¹

Aussi, en utilisant

void print(std::optional<SomeType> const& i);

ne serait en aucun cas optimale, puisque nous le ferions besoin Notre SomeType _ pour exister dans un std::optional sur le appelant - Côté, encore éventuellement (ou plutôt probablement) nécessitant une copie là-bas.

Question: Quelle serait une bonne approche moderne pour permettre des arguments facultatifs sans copier? Utilise un pointeur brut ici encore une approche raisonnable en C++ moderne?


¹: ironiquement la raison décrite pour la raison pour laquelle std::optional ne peut pas avoir de types de référence (la controverse sur la reproduction ou la transmission à l'affectation) ne s'applique pas dans le cas de std::optionals of const Références, car elles ne peuvent pas être affectées à.

32
Reizo

Ici le const* nature de l'argument i suggère l'intention, que le paramètre est facultatif car il peut être nullptr.

[...]

Alors quelle serait une bonne approche moderne pour permettre des arguments facultatifs sans copier?

Permettant un argument facultatif (pas dans le std::optional Sens, mais dans le sens sémantique), avec différentes variations de mise en œuvre, selon que l'argument facultatif soit présent ou non comme un candidat idéal pour la surcharge:

struct SomeType { int value; };

namespace detail {
    void my_print_impl(const SomeType& i) {
        std::cout << i.value;
    }    
}  // namespace detail

void my_print() {
    const SomeType default_i{42};
    detail::my_print_impl(default_i);
}

void my_print(const SomeType& i) { 
    detail::my_print_impl(i);
}

ou alors

namespace detail {
    void my_print_impl() {
        std::cout << "always print me\n";
    }    
}  // namespace detail

void my_print() {
    detail::my_print_impl();
}

void my_print(const SomeType& i) {
    detail::my_print_impl();
    std::cout << "have some type: " << i.value;
}

ou une variation similaire, en fonction de la mise en œuvre de votre mise en œuvre en fonction de l'existence/de la non-existence de l'argument facultatif.


Les références facultatives, sinon, sont essentiellement des pointeurs bruts et ce dernier peut aussi bien être utilisé (si la surcharge n'est pas applicable).

0
dfrib

C'est en fait ce que STD :: référence_wrapper a été fait pour. Voir aussi a du logique de combiner optionnelle avec référence_wrapper? Pour plus de raisonnement sur le point de l'utiliser, et quand ne pas l'utiliser.

0