Je me demandais s'il y avait un moyen de mettre cela sur une seule ligne?
if (auto r = getGlobalObjectByName(Word)) r->doSomething; // This works fine
if (!auto r = getGlobalObjectByName(Word)) r->doSomething; // Says "expected an expression"
if (auto r = getGlobalObjectByName(Word) == false) r->doSomething; // Also doesn't work.
J'ai également essayé de l'entourer de supports supplémentaires, mais cela ne semble pas fonctionner. Je trouve cela très pratique de le faire sur une seule ligne.
Depuis C++ 17, vous pouvez utiliser un initializer if-statement :
if (auto r = getGlobalObjectByName(Word); !r) r->doSomething;
La sémantique est:
if (init-statement; condition) statement
La seule différence avec l'instruction if "traditionnelle" est le init-statement
, qui initialise une variable dans la portée du bloc, similaire aux boucles for.
Si vous avez C++ 17, utilisez le formulaire if (init statement; condition)
. Sinon, vous avez trois choix:
Arrêtez d'essayer de garder tout cela sur une seule ligne. Par exemple:
auto r = getGlobalObjectByName(Word);
if (!r) r->doSomething();
Utilisez un else
:
if (auto r = getGlobalObjectByName(Word)) {} else r->doSomething();
(Notez que cela nécessite que r
soit un pointeur intelligent avec très une sémantique étrange pour la fonction operator bool()
. OTOH, je suppose que c'est en fait un court exemple) plutôt que votre code actuel).
Je pense que je n'utiliserais la forme else
que s'il était vraiment important de tout garder sur une seule ligne (pour conserver une mise en forme tabulaire du code par exemple).
Ce que vous essayez de faire est bien. En définissant la variable à l'intérieur de si vous restreignez sa portée . Cela permet de réduire le nombre de variables parasites une fois qu'elles ont atteint leur objectif.
En utilisant cette technique, si vous souhaitez suivre le chemin négatif , vous devez utiliser else comme ceci:
if(auto r = getGlobalObjectByName(Word))
{
r->doSomething();
}
else
{
// r == nullptr
// so do something else
}
Il existe également un moyen de le faire avec lambdas et C++ 14, mais cela semble plutôt idiot.
[](auto r){ if(!r)r->doSomething(); }(getGlobalObjectByName(Word));
En C++ 11, vous pouvez également faire ce désordre horrible (même idée, juste pas de auto
)
[](decltype(getGlobalObjectByName(Word)) r){ if(!r)r->doSomething(); }(getGlobalObjectByName(Word));
Ce n'est certainement pas mieux que cette version plus claire de C++ 11 mentionnée par Martin Bonner :
{
auto r = getGlobalObjectByName(Word);
if(!r)r->doSomething();
}
Ici, votre code indique clairement que vous voulez que r
ne soit présent que pendant la durée de l'instruction if.
Avant C++ 17, vous pouvez définir une classe wrapper, comme ici:
#include <utility>
template<typename T>
class NotT
{
T t;
public:
template<typename U>
NotT(U&& u) : t(std::move(u)) {}
explicit operator bool() const { return !t; }
T & value() { return t; }
T const& value() const { return t; }
};
template<typename T> NotT<T> Not(T&& t)
{
return NotT<T>(std::move(t));
}
#include <memory>
#include <iostream>
int main()
{
if(auto p=Not(std::make_shared<int>(2134)))
std::cout << "!p: p=" << p.value().get() << '\n';
else
std::cout << "!!p: p=" << p.value().get() << ", *p=" << *p.value() << '\n';
}