Il y a deux recherches qui sont faites pour le nom bar
. L'un est l'incompétent de recherche lors de la définition du contexte de l' foo
. L'autre argument est dépendante de recherche à chaque instanciation d'un contexte (mais le résultat de la recherche à chaque instanciation d'un contexte n'est pas autorisé à changer de comportement entre les deux instanciation des contextes).
Pour obtenir le comportement désiré, vous pouvez aller et de définir une stratégie de repli en fonction d'un fallback
d'espace de noms qui renvoie certains type unique
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
L' bar
fonction sera appelée si rien d'autre matchs, car les points de suspension a pire coût de la conversion. Maintenant, comprennent que les candidats dans votre fonction en utilisant la directive de l' fallback
, de sorte qu' fallback::bar
est inclus en tant que candidat à l'appel à l' bar
.
Maintenant, à voir si un appel à l' bar
résout à votre fonction, vous l'appellerez, et de vérifier si le type de retour est - flag
. Le type de retour d'une fonction choisie pourrait être nulle, de sorte que vous avez à faire certains opérateur virgule astuces pour obtenir autour de cela.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
Si notre fonction a été sélectionnée, alors l'opérateur virgule invocation sera de retour d'une référence à l' int
. Si non, ou si la fonction sélectionnée est retourné void
, puis l'invocation des retours void
à son tour. Alors la prochaine invocation avec flag
comme deuxième argument sera de retour un type qui a sizeof 1 si notre secours a été sélectionné, et un sizeof plus de 1 (le haut-opérateur virgule sera utilisé car void
est dans le mix) si quelque chose d'autre a été sélectionné.
Nous comparons les sizeof et déléguer à une struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
Cette solution est ambiguë si la fonction a des points de suspension trop. Mais cela semble être plutôt rare. Test à l'aide de la solution de repli:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
Et si un candidat est trouvé en utilisant l'argument dépendante de recherche
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
Pour tester non qualifiés de recherche lors de la définition du contexte, nous allons définir la fonction suivante au-dessus de foo_impl
et foo
(mettre le foo_impl modèle ci-dessus foo
, de sorte qu'ils ont tous les deux la même définition de contexte)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}