Click to See Complete Forum and Search --> : I am disgusted with my template


souldog
May 28th, 2004, 12:49 AM
I have made a std::map insert enforcer. It takes the pair
returned by insert and checks the second value to see if the
insert failed. If it did it throws an exception, if not it returns the
iterator held in the first element of the pair

so the use would look like

typedef std::map<blah, blahblah> BLAH_BLAH_MAP;

BLAH_BLAH_MAP bmap;

//this will throw if the insert fails
BLAH_BLAH_MAP::iterator it(MAP_INSERT_ENFORCE(bmap.insert(BLAH_BLAH_MAP::value_type(some_blah, some_blah_blah))("FRICKING INSERT FAILED ON BLAH_BLAH_MAP"));

...use iterator if you want


Now the problem is, I am disgusted on how I handled the template parameters. I don't like that I have to explicitely include
the first and second types of the pair as parameters. I just can not think of another way to make this possible.

any ideas.

here is the code for this enforcer


struct DefaultPredicate
{
template <class T>
static bool Wrong(const T& obj)
{
return !obj;
}
};

struct DefaultRaiser
{
template <class T>
static void Throw(const T&, const std::string& message, const char* locus)
{
throw std::runtime_error(message + '\n' + locus);
}
};


//MAKE AN ENFORCER FOR PAIRS WHICH CHECK 2ND AND RETURNS 1ST.. FOR STD::MAP::INSERT
//Ref should be std::pair<First, ?>& with or without const
template<typename Ref, typename First, typename P, typename R>
class PairEnforcerCheck2ndReturn1st
{
public:
PairEnforcerCheck2ndReturn1st(Ref t, const char* locus) : t_(t), locus_(P::Wrong(t.second) ? locus : 0)
{
}
First& operator*() const
{
if (locus_) R::Throw(t_, msg_, locus_);
return t_.first;
}

template <class MsgType>
PairEnforcerCheck2ndReturn1st& operator()(const MsgType& msg)
{
if (locus_)
{
// Here we have time; an exception will be thrown
std::ostringstream ss;
ss << msg;
msg_ += ss.str();
}
return *this;
}

private:
Ref t_;
std::string msg_;
const char* const locus_;
};

template <class P, class R, typename First, typename second>
inline PairEnforcerCheck2ndReturn1st<const std::pair<First, second>&, First, P, R>
MakePairCheck2ndReturn1stEnforcer(const std::pair<First, second>& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<const std::pair<First, second>&, P, R>(t, locus);
}

template <class P, class R, typename First, typename second>
inline PairEnforcerCheck2ndReturn1st<std::pair<First, second>&, first, P, R>
MakePairCheck2ndReturn1stEnforcer(std::pair<First, second>& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<std::pair<First, second>&, first, P, R>(t, locus);
}

#define MAP_INSERT_ENFORCE(exp) \
*MakePairCheck2ndReturn1stEnforcer<DefaultPredicate, DefaultRaiser>((exp), "Expression '" #exp "' failed in '" \
__FILE__ "', line: " STRINGIZE(__LINE__))

souldog
May 28th, 2004, 01:04 AM
Oh, and just to be clear.

1. This is a modification of Alexandrescu's ENFORCE

2. This works as expected, I just do not find it very elegant

Kheun
May 28th, 2004, 01:06 AM
Not sure if I am understand your question correctly. You are looking for implicitly specifying the template parameter, like this?


template <class P, class R, typename First=DefaultPredicate, typename second=DefaultRaiser>
inline PairEnforcerCheck2ndReturn1st<std::pair<First, second>&, first, P, R>
MakePairCheck2ndReturn1stEnforcer(std::pair<First, second>& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<std::pair<First, second>&, first, P, R>(t, locus);
}

#define MAP_INSERT_ENFORCE(exp) \
*MakePairCheck2ndReturn1stEnforcer<>((exp), "Expression '" #exp "' failed in '" \
__FILE__ "', line: " STRINGIZE(__LINE__))

souldog
May 28th, 2004, 01:18 AM
Thanks for the answer Kheun.

to answer you...no.

DefaultPredicate, DefaultRaiser are for the P and R template parameters.

I would like to not have to include std::pair explicitely at all and get rid of the First and second parameters.
so it looks something like


struct DefaultPredicate
{
template <class T>
static bool Wrong(const T& obj)
{
return !obj;
}
};

struct DefaultRaiser
{
template <class T>
static void Throw(const T&, const std::string& message, const char* locus)
{
throw std::runtime_error(message + '\n' + locus);
}
};

template<typename Ref, typename P, typename R>
class PairEnforcerCheck2ndReturn1st
{
public:
PairEnforcerCheck2ndReturn1st(Ref t, const char* locus) : t_(t), locus_(P::Wrong(t.second) ? locus : 0)
{
}
????& operator*() const
{
if (locus_) R::Throw(t_, msg_, locus_);
return t_.first;
}

template <class MsgType>
PairEnforcerCheck2ndReturn1st& operator()(const MsgType& msg)
{
if (locus_)
{
// Here we have time; an exception will be thrown
std::ostringstream ss;
ss << msg;
msg_ += ss.str();
}
return *this;
}

private:
Ref t_;
std::string msg_;
const char* const locus_;
};

template <class P, class R, typename T >
inline PairEnforcerCheck2ndReturn1st<const T&, P, R>
MakePairCheck2ndReturn1stEnforcer(const T& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<const T& , P, R>(t, locus);
}

template <class P, class R, typename T>
inline PairEnforcerCheck2ndReturn1st<T&, P, R>
MakePairCheck2ndReturn1stEnforcer(T& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<T&, P, R>(t, locus);
}

#define MAP_INSERT_ENFORCE(exp) \
*MakePairCheck2ndReturn1stEnforcer<DefaultPredicate, DefaultRaiser>((exp), "Expression '" #exp "' failed in '" \
__FILE__ "', line: " STRINGIZE(__LINE__))



the problem is where I have ???? in operator*
I need to be able to specify the type of t.first for Ref t, where Ref is arbitrary and has elements first and second. My thought was to some how use the fact that std::pair has a typedef type_first,
but I can not figure out how.

Kheun
May 28th, 2004, 02:13 AM
Please correct me if I am wrong. Actually, I am not familiar with the enforcer. However, your PairEnforcerCheck2ndReturn1st template class is using std::pair, I don't think you can get too far away from specifying the First and second type, at least I think it is logical to specify them for the PairEnforcerCheck2ndReturn1st class. If the pair is condensed as a type, the user of your class can specifys any none-std::pair type, causing your code to break.

However, if we can declare a typedef for the std::pair<First, second>, we can avoid repeating std::pair<>.


struct DefaultPredicate
{
template <class T>
static bool Wrong(const T& obj)
{
return !obj;
}
};

struct DefaultRaiser
{
template <class T>
static void Throw(const T&, const std::string& message, const char* locus)
{
throw std::runtime_error(message + '\n' + locus);
}
};


//MAKE AN ENFORCER FOR PAIRS WHICH CHECK 2ND AND RETURNS 1ST.. FOR STD::MAP::INSERT
template</*typename Ref,*/ typename First, typename second, typename P, typename R>
class PairEnforcerCheck2ndReturn1st
{
public:
typedef std::pair<First, second> EnforcerPair;


PairEnforcerCheck2ndReturn1st(EnforcerPair t, const char* locus) : t_(t), locus_(P::Wrong(t.second) ? locus : 0)
{
}

//EnforcerPair::first_type& operator*() const
EnforcerPair::first_type& operator*() const
{
if (locus_) R::Throw(t_, msg_, locus_);
return t_.first;
}

template <class MsgType>
PairEnforcerCheck2ndReturn1st& operator()(const MsgType& msg)
{
if (locus_)
{
// Here we have time; an exception will be thrown
std::ostringstream ss;
ss << msg;
msg_ += ss.str();
}
return *this;
}

private:
EnforcerPair t_;
std::string msg_;
const char* const locus_;
};

template <typename First, typename second, class P, class R>
inline PairEnforcerCheck2ndReturn1st<First, second, P, R>
MakePairCheck2ndReturn1stEnforcer(const PairEnforcerCheck2ndReturn1st<First, second, P, R>::EnforcerPair& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<First, second, P, R>(t, locus);
}

template <typename First, typename second, class P, class R>
inline PairEnforcerCheck2ndReturn1st<First, second, P, R>
MakePairCheck2ndReturn1stEnforcer(PairEnforcerCheck2ndReturn1st<First, second, P, R>::EnforcerPair& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<First, second, P, R>(t, locus);
}

Guysl
May 28th, 2004, 02:24 AM
souldog,
please don't flame me for my blind guess,
I'm newbie to templates and I don't really understant your code.
my guess (which might be not compiled):

typename PairEnforcerCheck2ndReturn1st::Ref::first_type operator*() const
{
if (locus_) R::Throw(t_, msg_, locus_);
return t_.first;
}

== edit ==
first_type

Regards,
Guy

souldog
May 28th, 2004, 04:10 AM
Thanks Guysl, that wont quite work. That is the kind of thing I was trying as well.

Khuen, I like your idea. I just got rid of the typedef since it would
not compile with it (could not deduce the types of first and second)
Also I need the pair member to be a reference


template<typename FIRST, typename SECOND, typename P, typename R>
class PairEnforcerCheck2ndReturn1st
{
public:

PairEnforcerCheck2ndReturn1st(std::pair<FIRST, SECOND>& t, const char* locus) : t_(t), locus_(P::Wrong(t.second) ? locus : 0)
{
}

FIRST& operator*() const
{
if (locus_) R::Throw(t_, msg_, locus_);
return t_.first;
}

template <class MsgType>
PairEnforcerCheck2ndReturn1st& operator()(const MsgType& msg)
{
if (locus_)
{
// Here we have time; an exception will be thrown
std::ostringstream ss;
ss << msg;
msg_ += ss.str();
}
return *this;
}

private:
std::pair<FIRST, SECOND>& t_;
std::string msg_;
const char* const locus_;
};

template <class P, class R, typename FIRST, typename SECOND>
inline PairEnforcerCheck2ndReturn1st<FIRST, SECOND, P, R>
MakePairCheck2ndReturn1stEnforcer(std::pair<FIRST, SECOND>& t, const char* locus)
{
return PairEnforcerCheck2ndReturn1st<FIRST, SECOND, P, R>(t, locus);
}


#define MAP_INSERT_ENFORCE(exp) \
*MakePairCheck2ndReturn1stEnforcer<DefaultPredicate, DefaultRaiser>((exp), "Expression '" #exp "' failed in '" \
__FILE__ "', line: " STRINGIZE(__LINE__))

Kheun
May 28th, 2004, 04:54 AM
I am really glad that you like it.

IMHO, I prefer to hide the details from the user that std::pair<> is being used by calling make_pair<>() in the constructor which also save us from having the need to have the helper function, MakePairCheck2ndReturn1stEnforcer(). In this case, it minimize the impact on the user if a different implementation of pair is chosen in the future.


PairEnforcerCheck2ndReturn1st(First f, Second s, const char* locus) : t_(make_pair<First, Second>(f,s)), locus_(P::Wrong(t.second) ? locus : 0)
{
}

souldog
May 28th, 2004, 05:06 AM
I would normally agree, but the reason this class exists
to use the macro MAP_INSERT_ENFORCE

this is going to be applied to the return value of std::map::insert
which is a ready made pair

Kheun
May 28th, 2004, 05:48 AM
Oh... after reading through your code again, I am finally understanding how your enforcer work. :thumb: