Listing 1: Unconsting and unrefing with trace

template<typename U>
class NONCONST
{
public:
  typedef U RET;
  static void trace()
  { std::cout << "Default NONCONST<U>" << std::endl; }
};

template<typename U>
class NONCONST<const U>
{
public:
  typedef U RET;
  static void trace()
  { std::cout << "NONCONST<const U>" << std::endl; }
};

template<typename U>
class NONREF
{
public:
  typedef U RET;
  static void trace()
  { std::cout << "Default NONREF<U>" << std::endl; }
};

template<typename U>
class NONREF<U&>
{
public:
  typedef U RET;
  static void trace()
  { std::cout << "NONREF<U&>" << std::endl; }
};

template<typename Func>
class X
{
  typedef Func::first_argument_type first_arg;
  typedef NONCONST<NONREF<first_arg>::RET>::RET raw_first_arg;
public:
  X( const raw_first_arg & theFirstArg) : m_theFirstArg(theFirstArg)
  { 
    NONREF<first_arg>::trace();
    NONCONST<NONREF<first_arg>::RET>::trace();
    std::cout << std::endl;
  }
  
private:
  raw_first_arg m_theFirstArg;
};

class func1
{
  typedef int first_argument_type;
};

class func2
{
  typedef const int first_argument_type;
};

class func3
{
  typedef int& first_argument_type;
};

class func4
{
  typedef const int& first_argument_type;
};

int main()
{
  int arg = 42;
  X<func1> x1(arg);
  X<func2> x2(arg);
  X<func3> x3(arg);
  X<func4> x4(arg);
  return 0;
}
— End of Listing —