6 votes

Façon élégante d'exprimer shift left OR right dans un template.

J'ai actuellement une fonction de modèle qui, en fonction de ses paramètres de modèle A et B, peut décaler une valeur vers la gauche ou vers la droite :

template <int A, int B> void f(X) {
// ...
if (A >= B)
{
  SetValue(X << (A-B));
}
else // (A < B)
{
  SetValue(X >> (B-A));
}

Lorsque j'instancie le modèle pour A<B je reçois un avertissement pour un décalage négatif à droite sur la première branche (inaccessible), et sinon je reçois un avertissement pour un décalage négatif à gauche sur la première branche. Notre base de code est exempte d'avertissements, ce qui n'est pas acceptable. Existe-t-il une alternative concise et lisible à ces deux déclarations de décalage ?

Des questions similaires (par exemple Déplacement dynamique vers la gauche OU la droite ) n'ont pas cet avertissement intempestif car la distance de décalage est une variable d'exécution.

0voto

Jack Aidley Points 3993

Vous pourriez ajouter un nouveau modèle, et le spécialiser de manière appropriée, par exemple :

template<bool b> int Shift(int i, int a, int b);

template<true> int Shift(int i, int a, int b) { return i << (a-b); }
template<false> int Shift(int i, int a, int b) { return i >> (b-a); }

Et ensuite l'invoquer comme Shift<(A >= B)>(X, A, B) . Cela devrait fonctionner.

0voto

Pete Becker Points 27371

En haut de ma tête :

template <int A, int B> struct whatever {
    static void f() {
        SetValue(X << (A - B));
    }
};

template <int A, int B, bool reversed> helper : whatever<A, B> {
};

template <int A, int B, true> : helper whatever<B, A> {
};

template <int A, int B> do_it : helper<A, B, B < A> {
};

template <int A, int B> void f() {
    return do_it<A, B>::f();
}

0voto

piwi Points 3445

Vous pourriez mettre les opérations de décalage dans des structures distinctes et utiliser std::conditional en C++11 :

template <typename A, typename B, typename X>
struct ShiftRight
{
    static void shift() { SetValue(X >> (A - B)); }
};

template <typename A, typename B, typename X>
struct ShiftLeft
{
    static void shift() { SetValue(X << (A - B)); }
};

template <typename A, typename B, typename X>
void f()
{
    typedef typename std::conditional<A >= B, ShiftLeft<A, B, X>, ShiftRight<A, B, X>>::type ShiftType;

    ShiftType::shift();
}

0voto

jrok Points 30472
template< int A, int B > void f(X)
{
    std::function< int(int, int) > shift =
        A < B
        ? [](int X, int N) { return X << N; }
        : [](int X, int N) { return X >> N; }

    SetValue( shift( X, std::max(A,B) - std::min(A,B) ) );
}

0voto

Mark B Points 60200

Je pense qu'un changement assez mineur serait simplement de remettre à zéro le décalage non exécuté avec un multiplicateur. Le compilateur peut toujours faire tout le travail au moment de la compilation :

template <int A, int B> void f(X) {
// ...
if (A >= B)
{
  SetValue(X << ((A < B) * (A-B)));
}
else // (A < B)
{
  SetValue(X >> ((A >= B) * (B-A)));
}

Je pense qu'une approche plus propre pourrait consister à envoyer à un modèle spécialisé dans le vrai/faux qui sait comment changer la bonne direction.

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