// PRMS Id: 6275
// Bug: unification fails for call to find_parameter_in_stack.

#include <stdio.h>
#include <stdlib.h>

const int max_stack_size = 20;

template <class T>
class Stack {
  private:
    T objects[max_stack_size];
    int nobjects;
  public:
    Stack(): nobjects(0) {}
    void push(const T&a) {
        if (nobjects >= max_stack_size) {
            fprintf(stderr,"Stack: overflow\n");
            abort();
          }
        objects[nobjects++] = a;
      }
    T pop() {
        if (!nobjects) {
            fprintf(stderr,"Stack: underflow\n");
            abort();
          }
        nobjects -= 1;
        T result = objects[nobjects];
        return result;
      }
    T top() const {
        if (!nobjects) {
            fprintf(stderr,"Stack: underflow\n");
            abort();
          }
        return objects[nobjects - 1];
      }
    int n() const { return nobjects; }
    T operator[](int i) { return objects[i]; }
};

template <class T>
class Parameter {
    T parameter_;
    int is_set_;
    int overrides_;
  public:
    Parameter(): is_set_(0), overrides_(0) {}
    void set(const T& a) { parameter_ = a; is_set_ = 1; }
    void override(int overrides = 1) { overrides_ = overrides; }
    const T& value() const { return parameter_; }
    int overrides() const { return overrides_; }
    int is_set() const { return is_set_; }
};

template <class T1, class T2>
T2
find_parameter_in_stack(Stack<T1>& stack, Parameter<T2>& (T1::*access)())
{
  T2 result;
  int have_result = 0;
  for (int i=stack.n()-1; i>=0; i--) {
      if ((stack[i].*access)().is_set()) {
          if (!have_result || (stack[i].*access)().overrides()) {
              result = (stack[i].*access)().value();
              have_result = 1;
            }
        }
    }
  return result;
}

class A {
  private:
    Parameter<int> a_;
  public:
    A() { }
    Parameter<int>& a() { return a_; }
};

int
main(int, char**)
{
  Stack<A> A_stack;
  A a1;
  A a2;
  a1.a().set(1);
  a2.a().set(2);
  A_stack.push(a1);
  A_stack.push(a2);

  int val = find_parameter_in_stack(A_stack, &A::a);

  printf("val = %d\n", val);
  if (val != 2)
    return 1;

  A_stack.pop();
  A_stack.pop();

  a1.a().override();

  A_stack.push(a1);
  A_stack.push(a2);

  val = find_parameter_in_stack(A_stack, &A::a);

  printf("val = %d\n", val);
  if (val != 1)
    return 1;

  return 0;
}
