有没有办法使用新的XXXX'取决于参数?

时间:2016-05-21 19:46:32

标签: c++

我正在研究一个使用反向抛光表示法模拟科学计算器的项目。我的文字,例如" 1"," 1.23"," 2/3"等等都存储在具有其类型的堆栈中。例如" 1"将被存储为整数," 1.23"作为Double等,使用我的类型(我出于各种原因定义了Double,Integer等)。

class Litteral {
  public:
     virtual QString toString () const = 0;
};

我想这样做:当用户输入一个运算符,比如+时,我需要在我的堆栈上弹出()两次,执行操作,然后按()。我已经完成了对运算符的识别。当用户键入+时,我执行给定的算法。 我的问题是当识别出+并且两个pop()完成后,我需要真正执行+并且我需要创建一个正确类型的对象。 例如,如果我有一个Integer和一个Double,我必须:

Litteral* l = new Double(pop1+pop2);

但如果我有两个整数,我必须:

Litteral* l = new Integer(pop1 + pop2);

...等 我可以使用大量的“如果'执行正确的"新的XXXX()",但我觉得这不是一个好的解决方案。 我还考虑使用模板方法,使用执行相应的算法,但我必须创建这个函数的尽可能多的版本,因为有可能的组合。这仍然是人类可能的,但同样,它并不会感到干净。 有没有干净的方法呢?

由于

编辑: 例如,当我弹出2个整数时,我想执行一个给定的操作。此操作的结果必须是整数。但结果并不总是一个整数,它取决于我流行的东西。如果是Integer和Double,结果将是Double。所以'新'的类型我必须做的事情取决于我流行的事情。 而且我不想用开关/倍数来实现它,如果'我不想这样做:

if ((typeid(*q1) == typeid(Integer)) && (typeid(*q2) == typeid(Double)))  { //...}

编辑2:

Literal& pop1 = stack.top(); 
stack.pop(); 
Literal& pop2 = stack.top(); 
stack.pop(); 
Literal& toAdd = (*pop1.clone() + *pop2.clone()); 

错误:不匹配'运营商+' (操作数类型是' Literal'' Literal')

课程:

class Literal { 
    public: virtual QString toString () const = 0; 
      virtual int getValue() const = 0; 
      virtual Litteral * clone() const = 0; 
      virtual Litteral& operator+(const Integer& l) = 0; 
}; 

class Integer: public Literal { 
    friend class LitteralManager; 
    int value; 
    public: 
      Integer(int v) :value(v) {} 
      Integer(const Entier& e) { value = e.getValue(); }; 
      virtual QString toString () const; 
      int getValue() const { return value; } 
      virtual Entier& operator+(const Entier& e);
      Entier * clone() const; 
};

3 个答案:

答案 0 :(得分:0)

#include <cassert>
#include <stack>

using namespace std;

struct Literal {
    virtual Literal* clone () const = 0;};

struct Double : Literal {
    Double* clone () const {
        return new Double(*this);}};

struct Integer : Literal {
    Integer* clone () const {
        return new Integer(*this);}};

int main () {
    stack<Literal*> x;

    x.push(new Double());
    x.push(new Integer());

    Literal* p = x.top();    // the Integer
    x.pop();
    Literal* q = p->clone(); // create a new Integer

    assert(typeid(*q) == typeid(Integer));

    return 0;}

答案 1 :(得分:0)

#include <cassert>
#include <typeinfo>

using namespace std;

struct Double;
struct Integer;

struct Literal {
    virtual Literal* operator + (const Literal&) const = 0;
    virtual Literal* operator + (const Double&)  const = 0;
    virtual Literal* operator + (const Integer&) const = 0;};

struct Double : Literal {
    Literal* operator + (const Literal& rhs) const {
        return rhs + *this;}

    Literal* operator + (const Double& rhs) const {
        return new Double;}

    Literal* operator + (const Integer& rhs) const {
        return new Double;}};

struct Integer : Literal {
    Literal* operator + (const Literal& rhs) const {
        return rhs + *this;}

    Literal* operator + (const Double& rhs) const {
        return new Double;}

    Literal* operator + (const Integer& rhs) const {
        return new Integer;}};

int main () {
    {
    Literal* p = new Double;
    Literal* q = new Double;
    Literal* r = *p + *q;
    assert(typeid(*r) == typeid(Double));
    }

    {
    Literal* p = new Double;
    Literal* q = new Integer;
    Literal* r = *p + *q;
    assert(typeid(*r) == typeid(Double));
    }

    {
    Literal* p = new Integer;
    Literal* q = new Double;
    Literal* r = *p + *q;
    assert(typeid(*r) == typeid(Double));
    }

    {
    Literal* p = new Integer;
    Literal* q = new Integer;
    Literal* r = *p + *q;
    assert(typeid(*r) == typeid(Integer));
    }

    return 0;}

答案 2 :(得分:0)

这是一个可能的解决方案:

#include <exception>
#include <functional>
#include <iostream>
#include <cassert>
#include <memory>

class Literal {
public:
  virtual ~Literal() = default;
};

class Double : public Literal {
public:
  Double(double val) : m_val(val) { }
  Double(const Double&) = default;
  Double(Double&&) = default;
  ~Double() = default;

  double value() const { return m_val; }

private:
  double m_val;
};

class Integer : public Literal {
public:
  Integer(int val) : m_val(val) { }
  Integer(const Integer&) = default;
  Integer(Integer&&) = default;
  ~Integer() = default;

  int value() const { return m_val; }

private:
  int m_val;
};

template <typename T> struct make_literal_result;
template <> struct make_literal_result<int> {
  using type = Integer;
};
template<> struct make_literal_result<double> {
  using type = Double;
};
template <typename T>
using make_literal_result_t = typename make_literal_result<T>::type;

template <typename T> std::unique_ptr<make_literal_result_t<T>> make_literal(T x) {
  return std::make_unique<make_literal_result_t<T>>(x);
}

template <typename Res, typename Fn>
Res dynamic_apply(Fn f, const Literal* val) {
  auto vald = dynamic_cast<const Double*>(val);
  if (vald != nullptr)
    return f(vald->value());
  auto vali = dynamic_cast<const Integer*>(val);
  if (vali != nullptr)
    return f(vali->value());
  throw std::invalid_argument("Invalid type");
}

std::unique_ptr<Literal> dynamic_plus(const Literal* x, const Literal* y) {
  auto curried_plus = [](auto val1) -> std::function<std::unique_ptr<Literal>(const Literal*)> {
    return [val1](const Literal* y) -> std::unique_ptr<Literal> {
      return dynamic_apply<std::unique_ptr<Literal>>([val1](auto val2) {
        return make_literal(val1 + val2);
      }, y);
    };
  };
  auto plus_x = dynamic_apply<std::function<std::unique_ptr<Literal>(const Literal*)>>(curried_plus, x);
  return plus_x(y);
}

int main() {
  Double x { 2.5 };
  Integer y { 3 };
  auto sum = dynamic_plus(&x, &y);
  auto sum_Double = dynamic_cast<Double*>(sum.get());
  assert(sum_Double != nullptr);
  std::cout << "sum is: " << sum_Double->value() << '\n';
  return 0;
}

dynamic_plus的一般概念是:plus_x中存储的结果是const Literal*并返回std::unique_ptr<Literal>的函数,其正文使用dynamic_apply通用lambda做它的工作。反过来,构建plus_xmake_literal向更高级别函数的另一个应用。 (然后,我们还需要使用std::function进行一些类型擦除,以便为dynamic_apply返回一些常见类型。)