10
votes

Fonction qui retourne un type inconnu

class Test
{
public:

 SOMETHING DoIt(int a)
 {
  float FLOAT = 1.2;
  int INT = 2;
  char CHAR = 'a';

  switch(a)
  {
  case 1: return INT;
  case 2: return FLOAT;
  case 3: return CHAR;
  }
 }
};


int main(int argc, char* argv[])
{  
 Test obj;
 cout<<obj.DoIt(1);    
    return 0;
}
Now, using the knowledge that a = 1 implies that I need to return an integer, etc., is there anyway Doit() can return a variable of variable data type?Essentially, with what do I replace SOMETHING ?PS: I'm trying to find a an alternative to returning a structure/union containing these data types.

7 commentaires

Je ne réinventerais pas la roue. Si vous n'avez pas de boost, obtenez-le maintenant! Vous ne voulez pas gâcher l'union et non-nul *;)


Compris, mais cela est destiné à être utilisé pour une application assez légère ciblée dans une large base d'utilisateurs qui n'utiliserait probablement pas de boost autrement. La solution Boost est assez belle mais s'il y a une alternative (ou une preuve que l'on n'existe pas), ce serait bien.


Il n'y a rien de tel dans la bibliothèque standard. Vous devez soit écrire le vôtre, ce qui n'est pas facile à la manière ou vous pouvez utiliser une bibliothèque externe. Il n'y a pas de problème avec la dépendance à la variante. Vous n'avez pas à expédier tous les boost avec votre code. Juste jeter un coup d'œil BCP outil de boost qui extrait les en-têtes requis pour votre code à travailler.


Que voulez-vous dire dans votre édition? Boost est 100% ANSI (ou ISO) C ++. Bien sûr, vous pouvez définir la même chose vous-même, mais vous vous sauveriez beaucoup de problèmes en utilisant Boost. (En dehors de cela, il n'existe pas d'applicaiton "trop ​​léger à utiliser boost". La chose intelligente à propos de Boost est que vous pouvez inclure les bibliothèques spécifiques dont vous avez besoin et rien d'autre. Si vous trouvez Boost.any utile, alors Inclure juste ça.


Par ANSI C ++, je veux dire que c'est inclus par défaut et ne doit pas être installé (comme STL). Et oui, comme je l'ai dit, la suggestion du BCP est la plus probablement ce que je vais suivre, mais ce n'est pas ce que j'avais à l'esprit à l'origine.


@JaCob tel que je comprends, vous avez un jeu de types connu connu . Utilisation de Boost :: Tout dans ce cas n'est pas recommandé, car il sert d'autres fins où Boost :: Variante ne peut pas servir. Boost :: La variante est beaucoup plus efficace et plus sûre pour votre cas. Aussi, boost :: Tout fait beaucoup de demandes de memroy dynamiques. En bref, il s'agit plus d'un type dynamique plutôt que d'un type de variante.


Bien sûr, désolé pour ça. Je n'ai pas consommé de boost avant et je viens d'inclure ce que j'ai lu dans l'un de vos premiers messages.


14 Réponses :


-1
votes

Si l'utilisateur sait ce qui est placé, vous pouvez utiliser un modèle pour résoudre ce problème. Sinon, je ne peux penser à aucune solution.


3 commentaires

Pourriez-vous être plus précis? La seule variable ici est le type de retour de la fonction.


Vous ne pouvez pas utiliser de modèles car le type de retour dépend de l'état d'exécution.


@Arak: Seulement si le int n'est pas connu à la compilation. Si c'est le cas, vous pouvez. Voir Stackoverflow.com/cetions / 1358427 / ...



29
votes

Vous pouvez utiliser boost :: n'importe quel ou boost :: variante < / code> pour faire ce que vous voulez. Je recommande boost :: variante Parce que vous connaissez la collection de types que vous souhaitez revenir.


C'est un exemple très simple, bien que vous puissiez faire beaucoup plus avec variante < / code>. Vérifiez la référence pour plus d'exemples:) xxx

la sortie: xxx

J'utiliserais boost :: Variante au lieu d'un Union car vous ne pouvez pas utiliser les types de non-POD intérieurs Union . En outre, boost :: Tout est génial si vous ne connaissez pas le type que vous avez géré. Sinon, j'utiliserais boost :: variante car il est beaucoup plus efficace et plus sûr.


Répondre à la question modifiée: Si vous ne voulez pas expédier Boost avec votre code, jetez un coup d'œil à < Code> bcp . La description de bcp du même lien:

L'utilitaire BCP est un outil pour extraire des sous-ensembles de boost, c'est utile pour booster les auteurs qui veulent distribuer leur bibliothèque séparément de Boost, et pour les utilisateurs de boost qui vouloir distribuer un sous-ensemble de boost avec leur application.

bcp peut également signaler sur quelles parties de Augmenter votre code dépend de, et Quelles licences sont utilisées par ces dépendances.


3 commentaires

Pour en faire une meilleure réponse à des fins didactiques, pourriez-vous inclure des liens vers les pages de référence pour Boost :: N'importe quel point de vue :: variante? Merci!


Arak, pourriez-vous ajouter le commentaire BCP à votre réponse?


@Jacob je n'ai pas vraiment utilisé bcp avant parce que Boost est toujours mon dans ma boîte à outils. Je vais ajouter un lien à ce que ce soit :)



8
votes

C ++ est une langue fortement typée et n'a aucun concept de type inconnu. Vous pouvez essayer d'utiliser Boost :: Tout, qui peut (sorte de) spécifier n'importe quel type. Je voudrais remettre en question la conception de votre fonction.


18 commentaires

+1 La nécessité de ce type de comportement peut être remplacée par une meilleure conception.


Jacob - Si vous décrivez ce que vous essayez réellement d'accomplir, nous pourrons peut-être suggérer une meilleure approche.


Ce serait trop compliqué. Mais le code de l'échantillon que j'ai affiché est assez indicatif de ce que je voudrais accomplir: j'ai besoin de renvoyer certaines données à l'aide d'une clé (c'est-à-dire que les données renvoyées peuvent avoir un type de données à partir d'un ensemble fini connu.


@Jacob La qualité des réponses que vous obtenez ici est directement proportionnée au détail de la question.


Humoris et au moins dire ce que l'ensemble est pour. :)


@Neil pendant que je comprends qu'il y a une odeur de code ici. Je ne peux pas comprendre comment allumeriez-vous la conception sans connaître la conception en premier lieu. J'ai utilisé Boost Boost :: Variante lors de la construction d'un Lexer pour l'une de mes classes collégiales et c'était le bon outil à mon avis. Même si C ++ est une langue fortement dactylographiée qui ne signifie pas à mon avis, il est faux tout le temps d'utiliser la variante ou l'autre de Boost.


@Arak j'ai dit que je voudrais remettre en question sa conception - il ne semble cependant pas vouloir répondre, cependant. La question signifie exactement que - "S'il vous plaît expliquer pourquoi vous pensez que c'est une bonne solution?" Toutes les conceptions doivent être interrogées, tout le temps.


@Neil: Il n'y a rien de plus à élaborer. Et la qualité d'une réponse dépend certainement du détail de la question, mais je pense que cela pourrait avoir quelque chose à voir avec la personne qui répondait aussi à la question :)


@Neil Pardon mon pauvre anglais;)


@Jacob ou le demander, probablement?


Oh, très certainement. Mais en regardant la plupart des réponses innovantes publiées dans ce fil, je ne pense pas que ce soit le problème ici.


Toutes ces réponses pourraient être bloquées dans un minimum local, où réside les réponses réelles ailleurs. Tandis que boost :: Tout ou boost :: variante peut être le meilleur moyen de retourner des types de variation, le retour des types de variation pourrait ne pas être le meilleur moyen de résoudre votre problème spécifique.


Comme je l'ai répété auparavant, et maintenant pour la dernière fois: c'est le problème spécifique. Le reste du projet a n'a pas d'importance .


Donc, votre projet complet consiste à appeler une fonction, à obtenir un type de retour variant et d'arrêter? Quelle partie de "Ce pourrait ne pas être la meilleure façon de résoudre la grande image" Ne vous en recevez pas?


Je ne poursuivrais plus cette ligne de discussion, car elle a dégénéré de caca-à-faire et semble avoir atteint un point où un refus têtu de voir le point de vue de l'auparavant a rendu un discours futur inutile.


Selon vos définitions. Je ne vois pas de "caca-shinging", juste des déclarations simples. Comment pouvez-vous apprendre quelque chose si vous pensez savoir tout?


@Gman: Il n'a jamais dit qu'il sait tout. Il n'a dit que la conception de son problème, les raisons pour lesquelles il ne révèlerait pas, conduit à cette question. Et pendant que je suis d'accord avec Neil que la conception est discutable (au sens de "nous devrions poser des questions à ce sujet"), car il y a un boost :: Tout et un boost :: variante , (Arak et) Je ne serais peut-être pas seul à voir des conceptions valides qui viennent à ce problème. Et non, je ne suis pas d'accord que "bien sûr, tu es un génie design devant qui nous devrions tous s'incliner" est une déclaration simple. C'est offensant.


@Neil: Oui, il est vraiment pourrait être amoureux de son design trop pour l'avoir disséqué ici. OTOH, il pourrait ne pas avoir d'influence sur elle ou / et il pourrait ne pas être autorisé à le révéler ici. S'il dit qu'il ne révélera pas les raisons, qui sommes-nous pour remettre en question cela? Il a posé une question, certains d'entre nous ont répondu que cela ne devrait probablement pas être nécessaire de poser de telles questions. S'il croit toujours que demander était nécessaire, c'est tout ce qu'il y a. Ce site est pour poser des questions et décider pour une réponse, après tout. FWIW, je considère que votre dernier commentaire est assez offensant et je l'ai marqué comme tel.



3
votes

Utilisez Boost :: Tout : < Pré> xxx


0 commentaires

1
votes

Vous pouvez utiliser un syndicat:

typedef union {
  int i;
  float f;
  char c;
} retType;

retType DoIt(int a){
  retType ret;

  float FLOAT = 1.2;
  int INT = 2;
  char CHAR = 'a';

  switch(a)
  {
    case 1: ret.i = INT; break;
    case 2: ret.f = FLOAT; break;
    case 3: ret.c = CHAR; break;
  }
  return ret;
}


1 commentaires

Il veut une alternative aux syndicats. Voir le P.s. à la fin de la question.



3
votes

Vous pouvez utiliser une structure contenant un Void * pointant sur la valeur que vous souhaitez renvoyer avec un taille_t indiquant que la taille de l'objet est renvoyée. Quelque chose comme ceci: xxx

N'oubliez pas que le vide * doit pointer sur une valeur résidant sur le tas (alloué dynamiquement à l'aide de neuf ou MALLOC ) Et l'appelant doit s'occuper de libérer l'objet attribué.

ayant dit cela, je pense que c'est une mauvaise idée globale.

EDIT: Vous voudrez peut-être également envisager d'inclure un drapeau indiquant ce qui a été retourné dans la structure ci-dessus afin que l'appelant puisse le donner un sens, à moins que l'appelant ne sait quel type à attendre.


0 commentaires

-3
votes

Quelque chose = vide *

Vous devez lancer la valeur retournée. Vous devez donc savoir ce qui est retourné. xxx


5 commentaires

Rappelez-vous simplement que les variables flottantes, Int et Char ipoptriront une fois la fonction une fois la fonction renvoie. Je ne suis pas sûr de quelles sont les conséquences.


-1 pour les adresses de retour des valeurs locales. De plus, un vide * est plutôt inutile si vous ne savez pas quel type il fait référence.


@Agnel: Les conséquences sont graves.


Les conséquences sont indéfinies, alors rien à grave.


@Gman: Je considère que les démons nasaux sont graves. :)



3
votes

Le moyen habituel d'atteindre quelque chose comme celui-ci est C, qui ne fonctionne pas toujours en C ++, est avec un syndicat et un champ de type: xxx

ceci ne fonctionne pas en C ++ Lorsque l'une des types de valeur possibles est une classe avec un constructeur non trivial, car il ne serait pas toujours clair que le constructeur doit être appelé. boost.variant utilise une version plus complexe de cette Approche pour fournir ce type de construction pour tout type de valeur en C ++.


0 commentaires

0
votes

Les bibliothèques de source Adobe ont également Adobe :: Any_regular_T , qui vous permet de stocker n'importe quel type aussi longtemps que celui-ci modélise le concept régulier . Vous serez la valeur de votre retour de la même manière que vous le feriez avec boost :: n'importe quel . (Il y a aussi une documentation sur la page liée de savoir comment Adobe :: anyregular_t diffère de boost :: Tout - bien sûr que le type que vous choisissez doit dépendre des exigences de votre code.)


0 commentaires

0
votes

Vous pouvez passer par référence à la place et être type et vérifier si cela fonctionnait en même temps, ne comporterait aucune bibliothèque supplémentaire (votre type de solution ANSI C ++):

bool DoIt (int i, int & r1)
{
  if (i==1) {r1 = 5; return true}
  return false;
}

bool DoIt (int i, double & r2)
{
  if (i==2) {r2 = 1.2; return true}
  return false;
}


1 commentaires

Cela fait partie d'une application dans laquelle il est essentiel de l'utiliser directement sans créer une nouvelle variable (à laquelle nous allions passer la référence).



-1
votes

Je pense que le problème concerne cette conception de la fonction. Avez-vous essayé surcharger?

class Test
{

public:

int DoIt(int a) {

  int INT = 2;
   return INT;

} 

float DoIt(float a) {

float FLOAT = 1.2; 
return FLOAT;

} 

char DoIt(char a) {

char CHAR = 'a'; 
return CHAR;

} 

};


int main(int argc, char* argv[])
{       
    Test obj;

//....

switch(a)
case 1: 
    cout<< obj.DoIt(1);    
break;

case 2:
cout<< obj.DoIt(1.01);   
break;

case 3:
cout<< obj.DoIt("1");   
break;

    return 0;
}


1 commentaires

L'élément variable ici est le type de rendement de la fonction et non les arguments.



3
votes

Edit: Boost :: Toute utilisation de BCP (Merci Arak) semble être la meilleure solution à ce jour, mais est-il possible de prouver (dans une certaine mesure) qu'il n'existe aucune solution ansi c ++ à ce problème?

Vous semblez un peu confus sur la terminologie ici.

Tout d'abord, appelons-le iso c ++, allons-nous? Il a été standardisé par l'ISO en 1998 et, depuis lors, c'est ce que les gens ont évoqué lorsqu'ils parlent de «standard C ++». Maintenant, que voulez-vous dire par une "solution ANSI C ++"?

  • une solution qui compile proprement en utilisant uniquement ANSI (ou ISO) C ++? Si oui, boost est la solution ANSI C ++
  • une solution déjà implémentée dans la bibliothèque standard ANSI C ++? Si oui, alors non, aucune solution de cette telle n'existe (et il n'y a pas de "preuve", autre que "aller lire dans la norme de langue et voir si vous pouvez trouver une telle classe. Si vous ne pouvez pas, ce n'est pas là".
  • Une solution que vous pouvez implémenter vous-même en utilisant uniquement ANSI C ++. Ensuite, la réponse est "Oui, vous pourriez aller copier le code source de BOOST".

    Je ne peux pas imaginer quel genre de "preuve" que vous rechercheriez. C ++ est un document sous forme de prose. Ce n'est pas une équation mathématique. Il ne peut pas être «prouvé», sauf en disant «aller lire la norme». Prouver que quelque chose est défini défini dans la langue ou dans la bibliothèque standard est facile - il suffit de souligner où dans la norme, il est décrit. Mais prouvant que quelque chose n'est pas il est essentiellement impossible - sauf en énumérant chaque phrase unique de la norme et documenter qu'aucun d'entre eux ne décrit ce que vous recherchez ce que vous recherchez . Et je doute que vous puissiez trouver quelqu'un prêt à faire que pour vous.

    Quoi qu'il en soit, la solution C ++ correcte est à utiliser boost. Ce n'est pas une solution de poids lourd. Boost est assez léger en ce que vous pouvez inclure exactement les bits dont vous avez besoin, sans dépendances sur le reste de la collection de la bibliothèque.

    de ce que vous avez décrit (une application de lumière pour une large base d'utilisateurs), il y a une raison nulle de ne pas utiliser de boost. Il peut simplifier votre code et réduire le nombre de bugs causés par la tentative de réinventer la roue. Lors de la distribution de l'exécutable compilé, il a un coût nul. La bibliothèque boost.any est, comme une grande quantité de boost, d'en-tête uniquement et est simplement compilée dans votre exécutable. Aucune bibliothèque distincte ne doit être distribuée.

    Il n'y a rien à gagné en essayant de réinventer la roue. Votre exécutable ne sera pas plus petite ou plus efficace, mais il sera plus de buggy.

    Et je suis prêt à parier que votre solution brassée à la maison pas soit ANSI C ++. Il s'appuiera sur une forme de comportement indéfini. Si vous souhaitez une solution ANSI-C ++, votre meilleur pari est boost.


15 commentaires

Je soupçonne qu'ils voulaient dire sans s'appuyer sur la boxe de la valeur retournée, étant donné leur PS.


Peut-être, mais si oui, la réponse est merveilleusement simple "Nope, n'existe pas". Bien que la demande de "preuve" me puzzle toujours.


[Ce] [1] est un exemple de preuve montrant que la réponse de cette personne ne fonctionnera pas. IMO, une preuve est juste une collection de déclarations prouvées , utilisées pour prouver la question à portée de main. La preuve que je demandais aurait pu faire la partie de la documentation que vous continuez à parler qui n'autorise pas explicitement cela sous une forme (laquelle je pense est difficile à trouver). [1]:


Et je cherchais une réponse simple (comme la plupart des alternatives postées ici) que j'aurais pu manquer. Si cela est impossible, et boost :: Tout est la meilleure alternative, alors c'est bien par moi, je vais utiliser BCP et l'ajouter (comme si j'ai dit dans mon post).


Pourquoi la spécification de langue pourrait-elle décrire ce qui est pas défini? Il vous dit ce que vous peut faire dans la langue. Si quelque chose n'est pas mentionné dans la norme, il ne fait pas partie de la langue. En général, le seul moyen de montrer que quelque chose peut pas être fait dans la langue est de ne pas le trouver dans le spécification. La norme ne dit pas "Aucun type de variante existe", cela décrit simplement les types qui font existent. Vous sonnez comme si vous voulez une preuve mathématique, qui n'est pas vraiment possible ou significative dans ce contexte.


Le lien que vous avez affiché ne "prouve" rien. Il montre une solution possible et un commentaire mentionne qu'il n'est pas légal. Ce n'est pas la preuve de quoi que ce soit. Le commentateur pourrait avoir tort (il n'est pas, mais il pourrait , et cela ne prouve donc rien).


Oui, personne n'a dit que les preuves doivent être correctes. Mais cela ne fait pas moins de preuve. J'étais juste curieux s'il y avait des déclarations uniques qui montreraient que ce n'est pas possible. Par exemple. Il est préférable de comparer le nombre de points flottant avec Epsilon plutôt que de les comparer directement. Pourquoi? En raison de la limitation inhérente à la manière dont les nombres de points flottants sont représentés, etc. Une preuve n'a pas toujours à contenir une équation, vous savez ( MATH.CSUSB.EDU/NOTES/PROWNS/PFNOT/NODE4.HTML )


Jacob, je vous suggère de prendre une classe logique ou de quelque chose. Votre raisonnement est terrible. Personne n'avait à dire que les preuves sont correctes? Un argument pourrait être valide et non sain, si c'est ce que vous voulez dire, mais par définition un argument non sain n'a aucune valeur. De même, un argument non valide n'a pas de valeur. Une preuve est une collection locale, ainsi que la connexion logique, qui prouve une conclusion être vraie . C'est comme dire: "2 + 2 = 5 n'est pas correct, mais c'est toujours une équation mathématique valide!"


Et si vous voulez une preuve, faites une dichotomie. Soit c'est dans la norme, soit pas. Quelque chose est valide ISO / ANSI C ++ si et seulement si c'est dans la norme. Par conséquent, si ce n'est pas dans la norme, il n'est pas valide ISO / ANSI C ++.


Et troisièmement, le lien que vous avez indiqué n'a rien à voir avec votre proposition. Une proposition qui est vraie reste vraie, peu importe la façon dont il est communiqué, tant que la méthode de communication suffit. Ainsi, cela pourrait ne pas être écrit en notation mathématique, mais tout ce que vous dites peut être transposé en notation mathématique. Votre lien décrit simplement différentes méthodes de preuve et non une preuve que les preuves n'ont pas besoin de contenir des équations mathématiques.


Je déteste énormément l'évidence, mais je suppose que cela doit être fait maintenant. Tout le monde écrit une preuve en pensant que c'est correct, mais il est tout à fait possible que quelqu'un vienne le long et la conserve, d'où ma déclaration sur les preuves n'était pas correcte. L'erreur humaine est assez courante, vous savez ..


Mais ce n'est plus appelé une preuve une fois qu'il est montré incorrect. Votre déclaration était "Oui, personne n'a dit que les preuves doivent être correctes. Mais cela ne fait pas moins de preuve.", Ce qui est très faux. Il fait en fait moins d'une preuve. En fait, cela ne fait pas une preuve du tout.


Une fois qu'il est démontré être incorrect, ce n'est pas une preuve. Mais avant cela ne se passe-t-il, n'est-ce pas toujours une soi-disant preuve? Et si les gens ne sont pas autorisés à poster de telles preuves en raison de raisons non énoncées ici, comment d'autres personnes peuvent-elles les réfuter?


En tout cas, j'ai ma réponse en tant que Jalf indiqué dans son poste d'origine. La modification de la question initiale est désormais un point sujet depuis la mise en œuvre de la mise en œuvre (preuve par exemple).


Je n'ai aucune idée de ce que vous venez de dire. Je n'ai jamais dit que les gens ne peuvent pas poster des preuves. Si une preuve est incorrecte, elle ne peut plus être considérée comme une preuve plus, juste une déclaration invalide.



6
votes

Si vous connaissez le type à la compilation, vous pouvez utiliser des modèles. Si le type dépend du temps d'exécution, l'utilisation des modèles n'est pas une option.

class Test
{
  template<int> struct Int2Type {};
  template<>    struct Int2Type<1> { typedef int value_type; };
  template<>    struct Int2Type<2> { typedef float value_type; };
  template<>    struct Int2Type<3> { typedef char value_type; };

public:
  template<int x> typename Int2Type<x>::value_type DoIt() {}; // error if unknown type used
  template<> typename Int2Type<1>::value_type DoIt<1>() { return 2; };
  template<> typename Int2Type<2>::value_type DoIt<2>() { return 1.2f; };
  template<> typename Int2Type<3>::value_type DoIt<3>() { return 'a'; };
};

int main()
{
  Test obj;
  cout << obj.DoIt<2>(); 
  return 0;
}


1 commentaires

Ceci est une solution magnifiquement simple si les chiffres sont connus au moment de la compilation. +1