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.
14 Réponses :
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. p>
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 code> n'est pas connu à la compilation. Si c'est le cas, vous pouvez. Voir Stackoverflow.com/cetions / 1358427 / ...
Vous pouvez utiliser C'est un exemple très simple, bien que vous puissiez faire beaucoup plus avec la sortie: p> J'utiliserais Répondre à la question modifiée: Si vous ne voulez pas expédier 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. P>
bcp peut également signaler sur quelles parties de
Augmenter votre code dépend de, et
Quelles licences sont utilisées par ces
dépendances. p>
blockQuote> p> boost :: n'importe quel Code>
ou boost :: variante < / code>
pour faire ce que vous voulez. Je recommande boost :: variante code> Parce que vous connaissez la collection de types que vous souhaitez revenir.
variante < / code>. Vérifiez la référence pour plus d'exemples:) p>
boost :: Variante code> au lieu d'un
Union code> car vous ne pouvez pas utiliser les types de non-POD intérieurs
Union code>. En outre,
boost :: Tout code> est génial si vous ne connaissez pas le type que vous avez géré. Sinon, j'utiliserais
boost :: variante code> car il est beaucoup plus efficace et plus sûr. P>
Boost code> avec votre code, jetez un coup d'œil à < Code> bcp code> . La description de
bcp code> du même lien: p>
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 b> avant parce que Boost est toujours mon dans ma boîte à outils. Je vais ajouter un lien à ce que ce soit :)
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. P>
+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 b> 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 code> ou
boost :: variante code> 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 b>.
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 code> et un
boost :: variante Code>, (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 i> ê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 I> 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.
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; }
Il veut une alternative aux syndicats. Voir le P.s. à la fin de la question.
Vous pouvez utiliser une structure contenant un N'oubliez pas que le ayant dit cela, je pense que c'est une mauvaise idée globale. P> EDIT: strong> 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. P> P> Void * code> pointant sur la valeur que vous souhaitez renvoyer avec un
taille_t code> indiquant que la taille de l'objet est renvoyée. Quelque chose comme ceci:
vide * code> doit pointer sur une valeur résidant sur le tas (alloué dynamiquement à l'aide de
neuf code> ou
MALLOC code>) Et l'appelant doit s'occuper de libérer l'objet attribué. P>
Quelque chose = vide *
Vous devez lancer la valeur retournée. Vous devez donc savoir ce qui est retourné. p>
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. :) code>
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: 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 ++. p> p>
Les bibliothèques de source Adobe ont également Adobe :: Any_regular_T Code>
, 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 code>. (Il y a aussi une documentation sur la page liée de savoir comment
Adobe :: anyregular_t code> diffère de
boost :: Tout code> - bien sûr que le type que vous choisissez doit dépendre des exigences de votre code.) p>
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; }
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).
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; }
L'élément variable ici est le type de rendement de la fonction et non les arguments.
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? P> blockQuote>
Vous semblez un peu confus sur la terminologie ici. P>
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 ++"? P>
- une solution qui compile proprement en utilisant uniquement ANSI (ou ISO) C ++? Si oui, boost est em> la solution ANSI C ++ LI>
- une solution déjà implémentée em> 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à". li>
- Une solution que vous pouvez implémenter vous-même em> en utilisant uniquement ANSI C ++. Ensuite, la réponse est "Oui, vous pourriez aller copier le code source de BOOST". LI> ul>
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 em> 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 em> 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 em> pour vous. P>
Quoi qu'il en soit, la solution C ++ correcte est em> à utiliser boost. Ce n'est pas une solution de poids lourd. Boost est assez léger en ce que vous pouvez inclure exactement em> les bits dont vous avez besoin, sans dépendances sur le reste de la collection de la bibliothèque. P>
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 code> 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. P>
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 em> plus de buggy. P>
Et je suis prêt à parier que votre solution brassée à la maison pas em> 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. P>
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 i>, 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 i> défini? Il vous dit ce que vous peut i> 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 i> ê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 i> 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 i> avoir tort (il n'est pas, mais il pourrait i>, 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 i>. 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 i> 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 B> 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.
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; }
Ceci est une solution magnifiquement simple si les chiffres sont connus au moment de la compilation. +1
AS de C ++ 17 Il y a std :: n'importe quel code>
et std :: variante code> A>, ce qui signifie que vous n'avez pas besoin de bibliothèque tierce pour cela. De la réponse de @ Arak, le code sera modifié un peu comme ci-dessous.
#include <variant>
#include <any>
#include <iostream>
typedef std::variant<char, int, double> myvariant;
myvariant fun(int value)
{
if(value == 0)
{
return 1001;
}
else if(value == 1)
{
return 3.2;
}
return 'V';
}
int main()
{
myvariant v = fun(0);
std::cout << v << std::endl;
v = fun(1);
std::cout << v << std::endl;
v = fun(54151);
std::cout << v << std::endl;
}
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 B> 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 B> connu B>. 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.