help-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Token types with constructor


From: Hans Aberg
Subject: Re: Token types with constructor
Date: Tue, 14 Sep 2004 19:08:53 +0200

At 12:01 +0200 2004/09/14, Akim Demaille wrote:
> > One can use static_cast instead
>
>Of course.

Noting the problem that the refcounted root class in a polymorphic
hierarchy should normally be virtual, in which case static_cast does not
work. So one has to drop the base class virtuality, and keep in mind to not
duplicate it in a multiple inheritance (not a big problem).

I made a ref<A> class where static_cast & dynamic_cast can be used side by
side (see below). I found that one can handle the 0 pointer problem by
letting ref<A>::operator->() hand over a pointer to a A() object, i.e., if
one want 0 to be given special semantics. I will simplify the writing of a
hierarchy even further.

Rather than supplying a refcount, it assumes that the classes already have
it. One can then use it as follows:
    class object_root {...};  // Supplies a refcount.

    // If one want to use static_cast, then "virtual" must be dropped.
    class A : public virtual object_root {...};

Then use
  class semantic_type {
  public:
    ref<object_root> object_;
    ...
  };

In the typing of grammar variables, one would use ref<A>. This way one gets
an easy, refcounted, static typing which Bison might help keeping track of.
So your concerns of a single polymorphic hierarchy goes away. In fact, the
parser taken away, I found it very hard to program with a single, untyped
polymorphic hierarchy. That is why I started with writing some ref<A>
classes by hand, without using templates.

So it looks as though one can set it up really nice.

template<class A>
class ref {
protected:
  A* data_;
  static A null_;

public:
  typedef ref<A> This;

  ref() : data_(0) {}
  ~ref() { shed(); }

  ref(const ref& x) : data_(x.copy()) {}
  ref& operator=(const ref& x) {
    if (data_ != x.data_) { shed(); data_ = x.copy(); }
    return *this;
  }

  ref(A* rp) : data_(rp) {}

  A* copy() const {
#if 0
    return (data_ == 0)? 0 : data_->copy();
#else
    if (data_ == 0) return 0;
    data_->increase_count();
    return const_cast<A*>(data_);
#endif
  }

  void shed() { if (data_ != 0)  data_->shed(); }

  ref<A> clone() const {
    if (data_ == 0) return 0;
    return new A(*data_);
  }

  // Operators that return pointer 0 when applicable:

  A* data() { return data_; }
  const A* data() const { return data_; }

#if 0 // Causes conflicts with operator&() in class maybe<>.
  A* operator&() { return data_; }
  const A* operator&() const { return data_; }
#endif

  // Operators that return reference to an object A() when applicable:

  A* operator->() { return (data_ == 0)? &null_ : data_; }
  const A* operator->() const { return (data_ == 0)? &null_ : data_; }

  A& operator*() { return (data_ == 0)? null_ : *data_; }
  const A& operator*() const { return (data_ == 0)? null_ : *data_; }

#if 1
  template<class B>
  explicit ref(B* op) : data_(dynamic_cast<A*>(op)) {}
#else
  template<class B>
  explicit ref(B* op, bool dynamic = true)
   : data_(dynamic? dynamic_cast<A*>(op) : static_cast<A*>(op)) {}
#endif

  template<class B>
  explicit ref(const B& op) : data_(dynamic_cast<A*>(op.copy())) {}

#if 0
  template<class T>
  struct cast {
    T item;
    cast(ref& x) : item(dynamic_cast<T>(x.data())) {}
    operator T() { return item; }
  };
#endif
};

  Hans Aberg






reply via email to

[Prev in Thread] Current Thread [Next in Thread]