Domanda

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;
}

Ora, utilizzando le conoscenze che a = 1 implica che ho bisogno di tornare un intero, ecc, c'è comunque Doit () può restituire una variabile del tipo di dati variabili?

In sostanza, con quello che faccio a sostituire QUALCOSA

PS:. Sto cercando di trovare un'alternativa al ritorno di una struttura / unione che contiene questi tipi di dati

È stato utile?

Soluzione

È possibile utilizzare boost::any o boost::variant per fare quello che vuoi. Vi consiglio boost::variant perché sai la raccolta di tipi che si desidera tornare.


Questo è un esempio molto semplice, anche se si può fare molto di più con variant. Controllare il riferimento per ulteriori esempi:)

#include "boost/variant.hpp"
#include <iostream>

typedef boost::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;
}

L'output:

1001
3.2
V

Vorrei usare boost::variant invece di un union perché non è possibile utilizzare i tipi di non-POD all'interno union. Inoltre, boost::any è grande se non si conosce il tipo si sta trattando. In caso contrario, vorrei utilizzare boost::variant, perché è molto più efficiente e più sicuro.


Rispondendo alla domanda modificato: Se non volete spedire Boost con il codice, dare un'occhiata a bcp . La descrizione del bcp dallo stesso link:

  

L'utilità BCP è uno strumento per   l'estrazione di sottoinsiemi di Boost, è   utile per gli autori Boost che vogliono   distribuire i loro biblioteca separatamente   da Boost, e per gli utenti che Boost   desidera distribuire un sottoinsieme di Boost   con la loro applicazione.

     

BCP può anche riferire su quali parti del   Amplia il tuo codice è dipendente, e   quali licenze sono utilizzati da coloro   dipendenze.

Altri suggerimenti

C ++ è un linguaggio fortemente tipizzato, e non ha il concetto di un tipo sconosciuto. Si potrebbe provare a utilizzare boost :: qualsiasi, che può (o quasi) specificare qualsiasi tipo. Vorrei mettere in discussione il disegno della vostra funzione, tuttavia.

Se si conosce il tipo in fase di compilazione è possibile utilizzare i modelli. Se il tipo dipende dal runtime, quindi utilizzando i modelli non è un'opzione.

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;
}

boost :: qualsiasi :

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

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

Il solito modo per ottenere qualcosa di simile è C, che non funziona sempre in C ++, è con un sindacato e un campo di tipo:

enum SomeType { INT, FLOAT, CHAR };
struct Something
{
    SomeType type;
    union
    {
        int i;
        float f;
        char c;
    };
};

Something DoIt(int a)
{
    Something s;
    switch (a)
    {
      case 1:
        s.type = INT;
        s.i = 2;
        break;
      case 2:
        s.type = FLOAT;
        s.f = 1.2;
        break;
      case 3:
        s.type = CHAR;
        s.c = 'a';
        break;
      default:
        // ???
    }
    return s;
}

Ciò non funziona in C ++, quando uno dei possibili tipi di valore è una classe con un costruttore non banale, perché non sarebbe sempre chiaro quale costruttore dovrebbe essere chiamato. Boost.Variant utilizza una versione più complessa di questo approccio per fornire questo tipo di costrutto per qualsiasi tipo di valore di C ++.

Si potrebbe utilizzare una struttura che contiene un void* indica il valore che si desidera venga restituito con un size_t che indica la dimensione dell'oggetto da restituire. Qualcosa di simile a questo:

struct Something {
    void *value;
    size_t size;
};

Si ricorda che la void* dovrebbe indicare un valore che risiede sul mucchio (ossia allocati dinamicamente utilizzando new o malloc) e il chiamante deve occuparsi di liberare l'oggetto allocato.

Detto questo, penso che sia una cattiva idea generale.

Modifica Si può anche prendere in considerazione tra cui un flag che indica ciò che è stato restituito nella struttura di cui sopra in modo che il chiamante possa dare un senso di esso, a meno che il chiamante sa che tipo aspettarsi

  

EDIT: boost :: qualsiasi utilizzando BCP (grazie Arak) sembra essere la soluzione migliore fino ad oggi, ma è possibile dimostrare (in qualche misura) che non esiste una soluzione ANSI C ++ a questo problema

?

Mi sembri un po 'confuso sulla terminologia qui.

In primo luogo, chiamiamolo ISO C ++, che ne dite? E 'stato standardizzato da ISO nel 1998, e da allora, questo è ciò che le persone hanno di cui quando si parla di "standard C ++". Ora, che cosa si intende per una "soluzione ++ ANSI C"?

  • Una soluzione che compila in modo pulito utilizzando solo ANSI (o ISO) C ++? Se è così, Boost è l'ANSI C ++ soluzione
  • Una soluzione già implementato in ANSI C ++ libreria standard? Se è così allora no, non esiste tale soluzione (e non v'è alcuna "prova", oltre che "andare a leggere attraverso il linguaggio standard e vedere se si può trovare una tale classe. Se non è possibile, non è lì".
  • Una soluzione si potrebbe implementare voi utilizzando solo ANSI C ++. Allora la risposta è "sì, si potrebbe andare copiare il codice sorgente dal Boost".

Non riesco a immaginare che tipo di "prova" si sarebbe cercando. C ++ è un documento in forma di prosa. Non è un'equazione matematica. Non può essere "provato", se non per dire "andare a leggere lo standard". Dimostrando che qualcosa di è definito nella lingua o nella libreria standard è facile - semplicemente indicare dove nello standard è descritto. Ma a dimostrazione che qualcosa di non è non v'è praticamente impossibile - se non per l'enumerazione tutti sola frase della norma, e il documento che nessuno di loro descrivere ciò che stai cercando . E dubito troverete qualcuno disposto a fare che per voi.

In ogni caso, la soluzione corretta standard di C ++ è per utilizzare Boost. Non è una soluzione di pesante. Boost è abbastanza leggero in quanto è possibile includere esattamente i bit necessari, senza dipendenze sul resto della collezione biblioteca.

Da quello che hai descritto (una leggera applicazione per un'ampia base di utenti), non v'è ragione zero non utilizzare Boost. Si può semplificare il codice e ridurre il numero di errori causati da cercando di reinventare la ruota. Quando si distribuiscono il file eseguibile compilato, che ha costo zero. La biblioteca Boost.Any è, come gran parte Boost, header-solo, ed è semplicemente compilato nel vostro eseguibile. Non ci sono librerie separate devono essere distribuiti.

Non c'è niente da guadagnare cercando di reinventare la ruota. Il tuo eseguibile non sarà più piccolo o più efficiente, ma si essere più buggy.

E io sono pronto a scommettere che la soluzione fatta in casa sarà non essere ANSI C ++. Essa si baserà su una qualche forma di comportamento non definito. Se si desidera una soluzione ANSI-C ++, la cosa migliore è Boost.

È possibile utilizzare un sindacato:

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;
}

Adobe Fonte Biblioteche ha anche adobe::any_regular_t , che consente di memorizzare qualsiasi tipo purché come modella la href="http://stlab.adobe.com/group__concept__regular__type.html" rel="nofollow noreferrer"> concetto regolare boost::any. (C'è anche la documentazione sulla pagina collegata su come adobe::any_regular_t differisce da boost::any -., Naturalmente, il tipo si sceglie dovrebbe dipendere i requisiti del codice)

Si potrebbe passare per riferimento invece ed essere typesave e verificare se ha funzionato allo stesso tempo, non avrebbe comportato alcuna libreria aggiuntiva sia (il vostro genere di ANSI C ++ soluzione):

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;
}

...

Trovo questa soluzione spesso più pulita in termini di design. E 'un peccato che le firme funciton non consentono più tipi come tipi di ritorno, ma in questo modo è possibile passare nulla.

Se l'utente sa ciò che viene messo in, è possibile utilizzare un modello per risolvere questo problema. In caso contrario, non posso pensare di qualsiasi soluzione.

Credo che il problema è di circa questo progetto funzioni. Hai provato a sovraccaricare?

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;
}

All'interno funzioni doit è possibile inserire più di codice e fare li chiamano altre funzioni per non ripetere il codice.

QUALCOSA = void *

È necessario lanciare il valore restituito, quindi bisogna sapere che cosa viene restituito.

void* 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;
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top