Transformez le résultat de (A-B) et (B-A) en unsigned, et masquez-le en plus (bitwise-and) avec (sizeof(int) - 1)
. Ceci efface l'avertissement pour GCC 5.5 et 6.3. Pour les versions plus récentes de GCC, aucun avertissement n'est généré.
template <int A, int B> void f(int X) {
// ...
if (A >= B)
{
SetValue(X << ((unsigned)(A-B) & (sizeof(int) - 1)));
}
else // (A < B)
{
SetValue(X >> ((unsigned)(B-A) & (sizeof(int) - 1)));
}
}
Nota pour répondre aux divers commentaires sur le comportement indéfini : le seul cas où la solution proposée pourrait provoquer un comportement indéfini est celui où l'on effectue un décalage d'une quantité supérieure à la largeur de bit de l'opérande. Cependant, ceci est protégé par la comparaison ; en supposant que la différence entre A et B est un nombre de décalage sûr, ce qui est implicite dans la question, alors if (A >= B)
garantit que seul un déplacement avec ce montant est effectivement exécuté. L'autre branche de la if
La déclaration est no exécuté et n'effectue donc pas de décalage et ne peut pas produire un comportement indéfini à partir du décalage (bien que si elle était exécutée, elle le ferait certainement).
Quelques commentateurs ont affirmé que la branche qui n'est pas exécutée peut encore provoquer un comportement indéfini. J'ai du mal à comprendre comment une telle erreur de compréhension peut se produire. Considérons le code suivant :
int *a = nullptr;
if (a != nullptr) {
*a = 4;
}
Or, si le déréférencement d'un pointeur nul provoque un comportement indéfini même lorsqu'il n'est pas exécuté, la condition de garde devient inutile. Ce n'est clairement pas le cas. Le code ci-dessus est parfaitement bien ; il assigne a
une valeur de nullptr
et ne déréférence pas ensuite a
en raison de la garde. Bien que des exemples aussi évidents (avec l'affectation à null immédiatement suivie d'une vérification de null) n'aient pas tendance à se produire dans le code réel, la "déréférence gardée" en général est un idiome commun. Il ne produit certainement pas en lui-même un comportement indéfini si le pointeur vérifié est effectivement nul ; c'est pourquoi la garde est utile.