// Bug 767777 - Fix compilation of sigc++/functors/slot.h on non-GCC

// Test interesting cases with and without template keyword.

// Explanations can be found in
// Bjarne Stroustrup, "The C++ Programming Language", 4th ed., section 26.3.1
// and in the C++ standard, section 14.2, clauses 4 and 5.
// (I've looked at a draft of the standard, but I assume that the final standard
// is identical.) The standard is more complete and (no surprise) more difficult
// to understand.

#include <iostream>

// 1. This case is a combination of two configure time checks.
class Thing
{
  public:
  Thing()
  {}

  template <class T>
  void operator()(T a, T b)
  {
    T c = a + b;
    std::cout << c << std::endl;
  }
};

template<class T2>
class OtherThing1
{
public:
  void do_something()
  {
    // thing_ does not depend on a template parameter.
    // The template keyword is optional.
    // Both calls to operator()<>() are correct.
    // gcc 5.3.1 accepts both calls.
    Thing thing_;
    thing_.template operator()<T2>(1, 2);
    thing_.operator()<T2>(1, 2);
  }
};

// 2.
template<class T1, class T2>
class OtherThing2
{
public:
  void do_something()
  {
    // thing_ depends on a template parameter, and is a member of the current
    // instantiation.
    // The draft standard is difficult to interpret. I have not found an example
    // in it for this case. Stroustrup does not discuss this case.
    // From the draft standard I get the impression that the template keyword
    // is optional, but gcc 5.3.1 requires it.
    thing_.template operator()<T2>(1, 2);
    thing_.operator()<T2>(1, 2);  // right or wrong?
  }
private:
  T1 thing_;
};

// 3. This is what should be tested at configure time.
template<class T1, class T2>
class OtherThing3
{
public:
  void do_something()
  {
    // thing_ depends on a template parameter, and is not a member of the
    // current instantiation.
    // The template keyword is required, and gcc 5.3.1 requires it.
    T1 thing_;
    thing_.template operator()<T2>(1, 2);
    thing_.operator()<T2>(1, 2);  // syntax error!
  }
};

int main()
{
  OtherThing1<int> thing1;
  thing1.do_something();

  OtherThing2<Thing, int> thing2;
  thing2.do_something();

  OtherThing3<Thing, int> thing3;
  thing3.do_something();

  return 0;
}
