Que diriez-vous d'une autre approche ?
Si vous faites de l'ostringstream un type optionnel, vous pouvez vérifier qu'il a été assigné avant de l'utiliser.
Imaginez une classe appelée lazy<>
qui construit paresseusement un objet quand c'est nécessaire, alors nous pourrions faire ceci :
int main()
{
using namespace std;
auto oss1 = lazy<std::ostringstream>();
auto oss2 = lazy<std::ostringstream>();
use(oss1) << "Hello";
if (oss1) cout << use(oss1).str() << endl;
if (oss2) cout << use(oss2).str() << endl;
if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
if_used(oss2,
[](auto& ss) { cout << ss.str() << endl; },
[](auto& oss) { cout << "oss2 is not used" << endl; });
use(oss2) << "Goodbye";
if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
return 0;
}
ce qui donne ce résultat :
Hello
Hello
oss2 is not used
Goodbye
Avantages :
Exemple complet ci-dessous avec un constructeur personnalisable :
J'ai utilisé std::experimental
pour le optional
mais vous pourriez tout aussi bien utiliser boost::optional
.
#include <iostream>
#include <experimental/optional>
#include <utility>
#include <type_traits>
#include <sstream>
using std::experimental::optional;
namespace detail {
template<class T, class Constructor>
struct lazy final
{
template<class Con , std::enable_if_t< not std::is_same<std::decay_t<Con>, lazy>::value > * = nullptr>
lazy(Con&& con)
: _constructor(std::forward<Con>(con))
{}
T& get() {
if (not bool(_opt)) {
_opt = _constructor();
}
return *_opt;
}
const T& get() const {
return *_opt;
}
bool used() const {
return bool(_opt);
}
operator bool() const {
return used();
}
private:
Constructor _constructor;
optional<T> _opt;
};
template<class T>
struct default_construct {
T operator()() const { return T(); }
};
struct no_action {
template<class T>
void operator()(T&) const { }
};
}
template<class T, class Constructor = detail::default_construct<T> >
auto lazy(Constructor&& con = detail::default_construct<T>())
{
return detail::lazy<T, std::decay_t<Constructor>>(std::forward<Constructor>(con));
}
template<class T, class Constructor>
auto& use(detail::lazy<T, Constructor>& l)
{
return l.get();
}
template<class T, class Constructor>
auto& use(const detail::lazy<T, Constructor>& l)
{
return l.get();
}
template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(detail::lazy<T, Constructor>& l, F&& f, Else&& e = detail::no_action())
{
if (l.used())
f(l.get());
else
e(l);
}
template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(const detail::lazy<T, Constructor>& l, F&& f, Else&& e)
{
if (l.used())
f(l.get());
else
e(l);
}
int main()
{
using namespace std;
auto oss1 = lazy<std::ostringstream>();
auto oss2 = lazy<std::ostringstream>();
use(oss1) << "Hello";
if (oss1) cout << use(oss1).str() << endl;
if (oss2) cout << use(oss2).str() << endl;
if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
if_used(oss2,
[](auto& ss) { cout << ss.str() << endl; },
[](auto& oss) { cout << "oss2 is not used" << endl; });
use(oss2) << "Goodbye";
if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
return 0;
}
0 votes
Eh bien, il y a [potentiellement] deux "choses" différentes demandées - qu'avez-vous essayé ?
0 votes
Définissez vos termes. Un exemple de programme dans lequel vous utiliseriez cette capacité serait d'une grande aide (avec un espace réservé où vous faites la "vérification de la nullité").
0 votes
Pouvez-vous préciser ce que vous entendez par "variable is empty/null" ? Voulez-vous dire que vous voulez savoir si le flux ne contient aucune donnée ?
0 votes
Désolé les gars. J'ai juste ajouté un peu plus d'informations.