Supponiamo le seguenti classi politiche che si prendono cura di un aspetto di un algoritmo:Evitando ramificazione in base al valore di ritorno della funzione che è un argomento di template
struct VoidF {
static void f() {
... // some code that has side effects
}
};
struct BoolF {
static bool f() {
bool res = ...; // some computation
return res;
}
};
La politica BoolF
è "la valorizzazione-aware": quando BoolF :: f() restituisce true
, l'algoritmo può uscire. VoidF
è "enhancement-inconsapevole", quindi restituisce void
(non voglio forzare l'utente della mia libreria a restituire bool
quando non significa niente per lui).
L'algoritmo è attualmente scritto in questo modo:
template <typename F>
struct Algorithm {
void run() {
... // some computation here
if (std::is_same<decltype(F::f()), bool>::value) {
if (F::f()) return;
} else
F::f(); // If F is VoidF, there should be no branching and some
// compiler optimizations will be enabled
... // more computation, unless F::f() got rid of it
}
};
Naturalmente, questo non funziona se Algorithm
è istanziato con VoidF
. C'è un modo per risolvere questo in modo che non ci dovrebbero essere ramificazioni in Algorithm<VoidF>::run()
come indicato dal commento?
ne dite 'run_method (f, std :: is_same {});' , con un 'run_method' opportunamente sovraccarico, ovviamente. Questo è noto come invio di tag di tipo. –
Una volta che il codice funziona, non ci saranno ramificazioni su nessun compilatore moderno. 'std :: is_same <> :: value' è una costante in fase di compilazione. Poiché ti preoccupi della ramificazione, un problema che è presente nell'output dell'assieme, non puoi chiedere come evitarlo senza prima esaminare il suddetto output dell'assieme. –
Puoi considerare uno spazio nomi invece di una struct e tag dispatching –