Hey, found some time and implemented a few more things today. Okay, so I know that @laserlight mentioned that my code will have undefined behaviour i.e. behaviour that's not been accounted by the standard and that I should implement code in a better way to support user defined types too. I've been thinking about it for a while now and I've come up with a few ideas but I'll let that stay for now. I have a working prototype right now that isn't in its best shape but here's the code:
Code:
#ifndef Z_DEBUG_H_INCLUDED
#define Z_DEBUG_H_INCLUDED
#include <bits/stdc++.h>
#define Debug(VarArgs...) \
{ \
std::string Str = #VarArgs; \
std::replace (Str.begin () , Str.end () , ',' , ' '); \
Str += " Debugging..."; \
std::stringstream SS (Str); std::istream_iterator<std::string> Iterator (SS); \
\
std::cerr << std::endl << std::endl \
<< "[FILE] : " << __FILE__ << '\n' \
<< "[DATE] : " << __DATE__ << '\n' \
<< "[TIME] : " << __TIME__ << '\n'; \
\
Error (Iterator , VarArgs); \
}
void Error (std::istream_iterator <std::string> Iterator)
{ std::cerr << '\n' << *Iterator; }
template <typename Type , typename... Args> void Error (std::istream_iterator <std::string> Iterator , const Type& Var , Args... ExtraArgs)
{
std::cerr << "\nValues of [" << *Iterator << "] : " << Var << '\n';
Error (++Iterator , ExtraArgs...);
}
template <typename T> class Debugger
{
private:
T Variable;
std::vector <T> VariableHistory;
public:
Debugger ();
Debugger (const Debugger <T>& Other);
Debugger (const T& Other);
~Debugger ();
operator T () const;
Debugger <T>& operator = (const Debugger <T>& Other);
Debugger <T>& operator += (const Debugger <T>& Other);
Debugger <T>& operator -= (const Debugger <T>& Other);
Debugger <T>& operator *= (const Debugger <T>& Other);
Debugger <T>& operator /= (const Debugger <T>& Other);
Debugger <T>& operator &= (const Debugger <T>& Other);
Debugger <T>& operator |= (const Debugger <T>& Other);
Debugger <T>& operator %= (const Debugger <T>& Other);
Debugger <T>& operator ^= (const Debugger <T>& Other);
Debugger <T>& operator <<= (const Debugger <T>& Other);
Debugger <T>& operator >>= (const Debugger <T>& Other);
Debugger <T>& operator ++ ();
Debugger <T>& operator -- ();
Debugger <T> operator ++ (int);
Debugger <T> operator -- (int);
template <typename Ty> friend std::istream& operator >> (std::istream& Stream , Debugger <Ty>& Input);
template <typename Ty> friend std::ostream& operator << (std::ostream& Stream , const Debugger <Ty>& Output);
template <typename Tp1 , typename Tp2> friend std::ostream& operator << (std::ostream& Stream , const Debugger <std::pair <Tp1 , Tp2>>& Output);
};
template <typename T> Debugger <T>::Debugger ()
: Variable ()
, VariableHistory ({Variable})
{ }
template <typename T> Debugger <T>::Debugger (const Debugger <T>& Other)
: Variable (Other.Variable)
, VariableHistory (Other.VariableHistory)
{ }
template <typename T> Debugger <T>::Debugger (const T& Other)
: Variable (Other)
, VariableHistory ({Variable})
{ }
template <typename T> Debugger <T>::~Debugger ()
{ }
template <typename T> Debugger <T>::operator T () const
{ return Variable; }
template <typename T> Debugger <T>& Debugger <T>::operator = (const Debugger <T>& Other)
{
Variable = Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator += (const Debugger <T>& Other)
{
Variable += Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator -= (const Debugger <T>& Other)
{
Variable -= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator *= (const Debugger <T>& Other)
{
Variable *= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator /= (const Debugger <T>& Other)
{
Variable /= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator &= (const Debugger <T>& Other)
{
Variable &= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator |= (const Debugger <T>& Other)
{
Variable |= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator %= (const Debugger <T>& Other)
{
Variable %= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator ^= (const Debugger <T>& Other)
{
Variable ^= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator <<= (const Debugger <T>& Other)
{
Variable <<= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator >>= (const Debugger <T>& Other)
{
Variable >>= Other.Variable;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator ++ ()
{
Variable++;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T>& Debugger <T>::operator -- ()
{
Variable--;
VariableHistory.push_back (Variable);
return *this;
}
template <typename T> Debugger <T> Debugger <T>::operator ++ (int)
{
Debugger <T> Copy (*this);
Variable++;
VariableHistory.push_back (Variable);
return Copy;
}
template <typename T> Debugger <T> Debugger <T>::operator -- (int)
{
Debugger <T> Copy (*this);
Variable--;
VariableHistory.push_back (Variable);
return Copy;
}
template <typename Ty> std::istream& operator >> (std::istream& Stream, Debugger <Ty>& Input)
{
Stream >> Input.Variable;
Input.VariableHistory.push_back (Input.Variable);
return Stream;
}
template <typename Ty> std::ostream& operator << (std::ostream& Stream, const Debugger <Ty>& Output)
{
Stream << '\n';
for (size_t i = 0; i < Output.VariableHistory.size (); i++)
Stream << "\n" << Output.VariableHistory [i];
return Stream;
}
template <typename Tp1 , typename Tp2> std::ostream& operator << (std::ostream& Stream , const Debugger <std::pair <Tp1 , Tp2>>& Output)
{
Stream << '\n';
for (size_t i = 0; i < Output.VariableHistory.size (); i++)
Stream << "\n{" << Output.VariableHistory[i].first << " , " << Output.VariableHistory[i].second << "}";
return Stream;
}
template <typename Tp1 , typename Tp2> std::ostream& operator << (std::ostream& Stream , const std::pair <Tp1 , Tp2>& Pair)
{
Stream << "{" << Pair.first << " , " << Pair.second << "}";
return Stream;
}
#endif // Z_DEBUG_H_INCLUDED
PS: Ignore that code for Pair for now.
And my code template:
Code:
#include <bits/stdc++.h>
#if 0
#include "z_debug.h"
#define char Debugger <char>
#define int32 Debugger <int>
#define uint32 Debugger <unsigned int>
#define int64 Debugger <long long>
#define uint64 Debugger <unsigned long long>
#define size_t Debugger <size_t>
#define float Debugger <float>
#define double Debugger <double>
#else
#define int32 int
#define uint32 unsigned int
#define int64 long long
#define uint64 unsigned long long
#define Debug(...)
#endif
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// A lot of other things but no point posting it....
int main (void)
{
return 0;
}
Well, it's been holding up fine for the few questions I've tried this template with although I've started to feel the problems that @laserlight may or may not have mentioned about. It is not as versatile as it should be (I will think of ways to better it). However, this is the only way I've come up with to show a variables' history but that doesn't mean I'm not going to be thinking of a better way.
Also, @laserlight, a question. Let's say I have the following code. I obviously don't want to be typecasting Debugger <T> to T explicitly when using the STL as that's unnatural. I want to make Debugger <T> behave exactly like T everywhere except for in Assignment operations for which I've provided operator overloads. Sure, there should be a better way to just write "min ((int)minimum , arr[i + k - 1] - arr[i])" as "min (minimum , arr[i + k - 1] - arr[i])" but idk how to do so and hence, your help.
Code:
int main (void)
{
cout.sync_with_stdio (false);
cin.tie (nullptr);
cout.precision (10);
cout << fixed;
int32 k = 3;
vector <int> arr {10,100,300,200,1000,100,85};
int32 minimum = INT_MAX;
sort (arr.begin () , arr.end ());
for (int i = 0; i < arr.size () - k + 1; i++)
minimum = min ((int)minimum , arr[i + k - 1] - arr[i]);
Debug(k , minimum);
return 0;
}
Thanks!
Note: I've learnt templates and most of modern c++ myself through online sources and e-books so I may have gaps in knowledge that is probably shown in the code. Apologies for that.