Juste au lieu de de :
if ( ch == 'A' || ch == 'B' || ch == 'C' || .....
Par exemple, pour le faire comme :
if ( ch == 'A', 'B', 'C', ...
Y a-t-il même un plus court manière de résumer les conditions ?
Juste au lieu de de :
if ( ch == 'A' || ch == 'B' || ch == 'C' || .....
Par exemple, pour le faire comme :
if ( ch == 'A', 'B', 'C', ...
Y a-t-il même un plus court manière de résumer les conditions ?
Dans ce cas, vous pouvez utiliser un switch
:
switch (ch) {
case 'A':
case 'B':
case 'C':
// do something
break;
case 'D':
case 'E':
case 'F':
// do something else
break;
...
}
Bien que cela soit légèrement plus verbeux que l'utilisation de strchr
il n'y a pas d'appel de fonction. Elle fonctionne également pour le C et le C++.
Notez que la syntaxe alternative que vous avez suggérée ne fonctionnera pas comme vous l'attendez en raison de l'utilisation de l'opérateur virgule :
if ( ch == 'A', 'B', 'C', 'D', 'E', 'F' )
Cette première comparaison ch
a 'A'
et rejette ensuite le résultat. Ensuite, 'B'
est évaluée et rejetée, alors 'C'
et ainsi de suite jusqu'à ce que 'F'
est évaluée. Ensuite, 'F'
devient la valeur de la conditionnelle. Puisque toute valeur non nulle évaluée à true dans un contexte booléen (et 'F'
est non nulle), alors l'expression ci-dessus sera toujours vraie.
Les modèles nous permettent de nous exprimer de cette manière :
if (range("A-F").contains(ch)) { ... }
Cela nécessite un peu de plomberie, que vous pouvez mettre dans une bibliothèque.
En fait, la compilation est incroyablement efficace (au moins sur gcc et clang).
#include <cstdint>
#include <tuple>
#include <utility>
#include <iostream>
namespace detail {
template<class T>
struct range
{
constexpr range(T first, T last)
: _begin(first), _end(last)
{}
constexpr T begin() const { return _begin; }
constexpr T end() const { return _end; }
template<class U>
constexpr bool contains(const U& u) const
{
return _begin <= u and u <= _end;
}
private:
T _begin;
T _end;
};
template<class...Ranges>
struct ranges
{
constexpr ranges(Ranges...ranges) : _ranges(std::make_tuple(ranges...)) {}
template<class U>
struct range_check
{
template<std::size_t I>
bool contains_impl(std::integral_constant<std::size_t, I>,
const U& u,
const std::tuple<Ranges...>& ranges) const
{
return std::get<I>(ranges).contains(u)
or contains_impl(std::integral_constant<std::size_t, I+1>(),u, ranges);
}
bool contains_impl(std::integral_constant<std::size_t, sizeof...(Ranges)>,
const U& u,
const std::tuple<Ranges...>& ranges) const
{
return false;
}
constexpr bool operator()(const U& u, std::tuple<Ranges...> const& ranges) const
{
return contains_impl(std::integral_constant<std::size_t, 0>(), u, ranges);
}
};
template<class U>
constexpr bool contains(const U& u) const
{
range_check<U> check {};
return check(u, _ranges);
}
std::tuple<Ranges...> _ranges;
};
}
template<class T>
constexpr auto range(T t) { return detail::range<T>(t, t); }
template<class T>
constexpr auto range(T from, T to) { return detail::range<T>(from, to); }
// this is the little trick which turns an ascii string into
// a range of characters at compile time. It's probably a bit naughty
// as I am not checking syntax. You could write "ApZ" and it would be
// interpreted as "A-Z".
constexpr auto range(const char (&s)[4])
{
return range(s[0], s[2]);
}
template<class...Rs>
constexpr auto ranges(Rs...rs)
{
return detail::ranges<Rs...>(rs...);
}
int main()
{
std::cout << range(1,7).contains(5) << std::endl;
std::cout << range("a-f").contains('b') << std::endl;
auto az = ranges(range('a'), range('z'));
std::cout << az.contains('a') << std::endl;
std::cout << az.contains('z') << std::endl;
std::cout << az.contains('p') << std::endl;
auto rs = ranges(range("a-f"), range("p-z"));
for (char ch = 'a' ; ch <= 'z' ; ++ch)
{
std::cout << ch << rs.contains(ch) << " ";
}
std::cout << std::endl;
return 0;
}
résultat attendu :
1
1
1
1
0
a1 b1 c1 d1 e1 f1 g0 h0 i0 j0 k0 l0 m0 n0 o0 p1 q1 r1 s1 t1 u1 v1 w1 x1 y1 z1
Pour référence, voici ma réponse initiale :
template<class X, class Y>
bool in(X const& x, Y const& y)
{
return x == y;
}
template<class X, class Y, class...Rest>
bool in(X const& x, Y const& y, Rest const&...rest)
{
return in(x, y) or in(x, rest...);
}
int main()
{
int ch = 6;
std::cout << in(ch, 1,2,3,4,5,6,7) << std::endl;
std::string foo = "foo";
std::cout << in(foo, "bar", "foo", "baz") << std::endl;
std::cout << in(foo, "bar", "baz") << std::endl;
}
Encore une réponse à cette question trop souvent posée, que j'inclus juste pour être complète. Entre toutes les réponses ici, vous devriez trouver quelque chose qui fonctionne dans votre application.
Une autre option est donc une table de consultation :
// On initialization:
bool isAcceptable[256] = { false };
isAcceptable[(unsigned char)'A'] = true;
isAcceptable[(unsigned char)'B'] = true;
isAcceptable[(unsigned char)'C'] = true;
// When you want to check:
char c = ...;
if (isAcceptable[(unsigned char)c]) {
// it's 'A', 'B', or 'C'.
}
Vous pouvez vous moquer des moules statiques de style C, mais ils font le travail. Je suppose que vous pourriez utiliser un std::vector<bool>
si les réseaux vous empêchent de dormir la nuit. Vous pouvez également utiliser des types autres que bool
. Mais vous comprenez l'idée.
Il est évident que cela devient encombrant avec, par exemple, les éléments suivants wchar_t
et pratiquement inutilisable avec les codages multi-octets. Mais pour votre char
par exemple, ou pour tout ce qui se prête à une table de consultation, il fera l'affaire. YMMV.
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.