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__))
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__))