7
votes

Comment faire un modèle de fonction la moins prioritaire pendant ADL?

J'ai un problème où je voudrais fournir une version générique d'une fonction foo code> qui ne peut être appliquée que lorsqu'il n'y a absolument aucune autre correspondance pour une invocation. Comment puis-je modifier le code suivant de telle que last_resort :: foo code> est une correspondance pire pour dérivé :: Type code> que base :: foo code>? J'aimerais trouver une solution qui n'implique pas de modifier la définition de la barre code> et qui préserverait le type de l'argument de last_resort :: FOO code>.

#include <iostream>

namespace last_resort
{

template<typename T> void foo(T)
{
  std::cout << "last_resort::foo" << std::endl;
}

}

template<typename T> void bar(T)
{
  using last_resort::foo;
  foo(T());
}

namespace unrelated
{

struct type {};

}

namespace base
{

struct type {};

void foo(type)
{
  std::cout << "base::foo" << std::endl;
}

}

namespace derived
{

struct type : base::type {};

}

int main()
{
  bar(unrelated::type()); // calls last_resort::foo
  bar(base::type());      // calls base::foo
  bar(derived::type());   // should call base::foo, but calls last_resort::foo instead

  return 0;
}


0 commentaires

4 Réponses :


1
votes

Vous ne pouvez pas faire grand chose à ce sujet. Les deux fonctions FOO sont dans l'ensemble de surcharge. Mais votre Last_Resort One est un meilleur match simplement parce qu'il ne nécessite pas de conversion contrairement à la base :: FOO pour dérivé :: Type (). Ce n'est que dans le cas où deux candidats sont "tout aussi bien" à juger par les paramètres et les conversions possibles, un non-modèle est préféré.


3 commentaires

C'est vrai, mais je me demande s'il y a un moyen d'introduire une conversion "cachée" en foo en augmentant celui-ci avec des paramètres supplémentaires avec des valeurs par défaut?


Je ne pense pas que ça va marcher. D'après ce que je peux dire au "meilleur" que vous puissiez obtenir est une ambiguïté afin que la compilation échoue. Mais peut-être, il me manque aussi quelque chose.


La solution semble être de décorer le type de retour Last_Resort :: FOO S avec quelque chose comme Désactiver_if_foo_exists :: Type , qui utiliserait Sfinae pour vérifier un < Code> FOO fonction. Si l'on existe, last_resort :: FOO serait supprimé de l'ensemble de la surcharge.



0
votes

Vous pouvez fournir une surcharge de la barre code> pour type dérivé :: Type Code> Après la déclaration de dérivé :: Type Code>. Cela peut être dans Espace de noms dérivé code> ou non.

void bar(derived::type)
{
  foo(derived::type());
}


0 commentaires

3
votes

Ce serait à peu près aussi mauvais que possible:

struct badParam { 
    badParam() { }
    operator int() { return 42; }
};
namespace last_resort {
  template <typename T> void foo(T t, int dummy = badParam(), ...) {
    std::cout << "last_resort::foo" << std::endl;
  }
}


3 commentaires

Merci. Je pense que l'ajout du Badparam est suffisante pour la modifier, mais elle efface le type de t dans la conversion.


Eh bien, pour un dernier cas, vous ne pouvez généralement pas compter sur T de toute façon, car vous obtenez tous les types étranges. Mais le sauvegarde est difficile. La déduction de l'argument de modèle ne produit pas ces conversions définies par l'utilisateur.


Post antique, mais la pensée aléatoire: que diriez-vous d'utiliser l'original badparam , mais faisant Badparam un type de modèle avec un argument de modèle Pointeur de valeur sur la fonction réelle pour invoquer, ce qu'il fait donc dans son constructeur.



1
votes

Last_Resort :: FOO peut être supprimé de l'ensemble de surcharge avec désactiver_if . L'idée est de désactiver last_resort :: foo (t) si foo (t) est autrement bien formé. Ceci provoque last_resort :: FOO (t) Pour être la pire match pour FOO : xxx

la sortie: < pré> xxx

Cette réponse explique comment construire une solution pour vérifier l'existence d'une fonction ( foo ) renvoyant vide .


0 commentaires