2015-05-15 13 views
7

Voglio implementare una struttura di dati dell'albero delle espressioni aritmetiche semplice in C++, in modo tale che un albero di espressioni sia inizializzato da: ExprTree(operator, expression1, expression2). Ecco un esempio di come dovrebbe funzionare:Struttura dati dell'albero di espressione

double x = 1, y = 2, z = 0.5; 
expr1 = ExprTree('*', x, y); // expr1 = 1 * 2 = 2 
expr2 = ExprTree('-', expr1, z); // expr2 = (1 * 2) - 0.5 = 1.5 
cout << expr2.str() << endl; // ((1 * 2) - 0.5) 
cout << expr2.eval() << endl; // 1.5 

Ecco come il mio codice è finora:

template<class operand_type> 
class ExprTree 
{ 
public: 
    ExprTree(const char op_, operand_type& operand1_, operand_type& operand2_) 
    { 
     op = op_; 
     operand1 = operand1_; 
     operand2 = operand2_; 
    } 
    double eval() const; 
    std::string str() const; 
private: 
    char op; 
    typename operand_type operand1, operand2; 
}; 

template<class operand_type> 
std::string ExprTree<operand_type>::str() const 
{ 
    std::ostringstream os; 
    std::string op1, op2; 
    if (typeid(*operand1) == typeid(ExprTree)) 
     op1 = operand1->str(); 
    else 
     op1 = std::string(*operand1); 
    if (typeid(*operand2) == typeid(ExprTree)) 
     op2 = operand1->str(); 
    else 
     op2 = std::string(*operand2); 
    os << "(" << op1 << " " << op << " " << op2 << ")"; 
    return os.str(); 
} 

Tuttavia, ottengo questo errore quando compilo il codice:

left of '->write' must point to class/struct/union/generic type 

Apprezzerei se qualcuno mi aiutasse con questo errore e possibilmente fornire alcuni suggerimenti su come dovrei implementare questa struttura dati. Btw, sono molto nuovo di C++.

+1

Non vedo il pezzo di codice rilevante (la chiamata a 'write' o la sua definizione). – Unimportant

+0

Ho modificato il codice. Dovrebbe leggere 'str' invece di' write'. – Randolph

+0

È necessario aggiungere il tipo di modello quando si crea un'istanza dell'oggetto: 'ExprTree expr1 ('*', x, y);' La riga successiva 'ExprTree ('-', expr1, z)' richiede un costruttore che può prendere 2 tipi diversi di operandi. – Unimportant

risposta

2

ci sono una serie di problemi nel codice:

  1. Si utilizza membro del puntatore-> operatore variabili membro operando1 e operando2

  2. È necessario due tipi diversi negli argomenti del modello per inizializzare l'oggetto con diversi tipi di argomenti.

  3. Classi/costruttori non eseguono il rilevamento automatico di tipi come le funzioni. Significa che non puoi fare una cosa come ExprTree('*', x, y);. È necessario specificare gli argomenti del modello etere o utilizzare una funzione modello aggiuntiva per costruire l'oggetto della classe modello ExprTree. Vedi questo answer.

  4. Il if (typeid(*operand1) == typeid(ExprTree)) viene valutata in fase di esecuzione, in modo da otterrete un errore di compilazione perché si tenta di chiamare il metodo str() e passare lo stesso oggetto da std :: string

I preferisce la seguente soluzione:

#include <string> 
#include <iostream> 
#include <sstream> 

template<typename operand_type_A, typename operand_type_B> 
class ExprTree 
{ 
public: 
    ExprTree(){}; 
    ExprTree(const char op_, const operand_type_A& operand1_, const operand_type_B& operand2_) { 
     op = op_; 
     operand1 = operand1_; 
     operand2 = operand2_; 
    }; 
    double eval() const; 
    std::string str() const; 

private: 
    char op; 
    operand_type_A operand1; 
    operand_type_B operand2; 
}; 

template<typename operand_type_A, typename operand_type_B> 
ExprTree<operand_type_A, operand_type_B> makeExpr(const char op, const operand_type_A& operand1, const operand_type_B& operand2) 
{ 
    return ExprTree<operand_type_A, operand_type_B>(op, operand1, operand2); 
} 

template<typename T> 
std::string ToString(const T& x) 
{ 
    return x.str(); 
} 

template<> 
std::string ToString<double>(const double& x) 
{ 
    return std::to_string(x); 
} 

template<typename operand_type_A, typename operand_type_B> 
std::string ExprTree<operand_type_A, operand_type_B>::str() const { 
    std::ostringstream os; 
    std::string op1, op2; 
    op1 = ToString(operand1); 
    op2 = ToString(operand2); 
    os << "(" << op1 << " " << op << " " << op2 << ")"; 
    return os.str(); 
} 

int main() 
{ 
    double x = 1, y = 2, z = 0.5; 
    std::cout << makeExpr('-', makeExpr('*', x, y), z).str() << std::endl; 
    return 0; 
} 

Produce il seguente stringa:

01.235.
((1.000000 * 2.000000) - 0.500000) 

Si può provare here.

2

Quando si dice:

operand1->str(); 

Si dovrebbe dire invece:

operand1.str(); 

Perché operand1 non è un puntatore, ma una variabile membro.

Il messaggio di errore

sinistra '-> str' deve puntare a classe/struttura/unione/tipo generico

in pratica dice che la sinistra dell'operatore -> deve essere un puntatore (non è). (Si dice anche che deve puntare a una classe o simile, non a un intero, per esempio).